Merge pull request #2461 from SiboVG/issue-2456-1

[#2456] Overhaul of sim table GUI
This commit is contained in:
Joe Pfeiffer 2024-03-23 19:21:55 -06:00 committed by GitHub
commit 6f4d11447c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
55 changed files with 1381 additions and 826 deletions

View File

@ -452,12 +452,10 @@ simedtdlg.but.delete = Delete
simedtdlg.title.Editsim = Edit simulation
simedtdlg.title.MultiSimEdit = Multi-simulation edit
simedtdlg.title.MultiSimEdit.ttip = <html>You are editing the following simulations:<br>
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 = <html>Are you sure you want to <b>discard</b> your <b>changes</b> to this simulation?</html>
SimulationConfigDialog.CancelOperation.msg.undoAdd = <html>Are you sure you want to <b>undo adding</b> this simulation?</html>
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 = <html>Are you sure you want to <b>discard</b> your <b>changes</b> to this simulation?</html>
SimulationEditDialog.CancelOperation.msg.undoAdd = <html>Are you sure you want to <b>undo adding</b> this simulation?</html>
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 = <html><i>This operation cannot be undone.</i>
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 = <i><font color=\"red\">Out of date</font></i><br>Click
simpanel.ttip.external = <i>Imported data</i>
simpanel.ttip.notSimulated = <i>Not simulated yet</i><br>Click <i><b>Run simulations</b></i> to simulate.
simpanel.ttip.noData = No simulation data available.
simpanel.ttip.noWarnings = <font color=\"gray\">No warnings.</font>
simpanel.ttip.warnings = <font color=\"red\">Warnings:</font>
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.

View File

@ -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 = .قم بإجراء عمليات حسابية بتقريب للأرض المسطحة. كافية للرحلات على إرتفاعات منخفضة

View File

@ -283,8 +283,8 @@ simedtdlg.title.Editsim = Uprav simulaci
simedtdlg.lbl.Simname = Jméno simulace:
simedtdlg.tab.Launchcond = Startovací podmínky
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.

View File

@ -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 Ausdrücke
simedtdlg.tab.Exportdata = Daten exportieren
SimulationConfigDialog.tab.Exportdata = Daten exportieren
simedtdlg.lbl.Motorcfg = Motorkonfiguration:
simedtdlg.lbl.ttip.Motorcfg = Motorkonfiguration auswählen
simedtdlg.combo.ttip.motorconf = Die Motorkonfiguration auswählen.

View File

@ -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 = <html>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 = <html><i>Extensiones del simulador</i> 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.

View File

@ -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 = <html>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 = <html><i>Les auditeurs de simulation</i> sont une fonction avanc\u00E9e qui permet \u00E0 l'utilisateur d'\u00E9crire du code pour suivre et interagir avec la simulation.

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -1731,9 +1731,9 @@ simedtdlg.lbl.ttip.Turbulenceintensity1 = <html>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 = <html><i>Observa\u00e7\u00e3o da simula\u00e7\u00e3o</i> \u00e9 um recurso avan\u00e7ado que permite que o usu\u00e1rio escreva c\u00f3digo para observar e interagir com a simula\u00e7\u00e3o.

View File

@ -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.

View File

@ -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.

View File

@ -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 = <html>\u98CE\u5411, 0-360\u5EA6. <br>0 \u662F\u5317\u98CE,<br> 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 = <html><i>\u4EFF\u771F\u76D1\u542C\u5668(Simulation Listener)</i>\u662F\u4E00\u4E2A\u9AD8\u7EA7\u7279\u6027,\u5141\u8BB8\u7528\u6237\u81EA\u5B9A\u4E49\u4EE3\u7801\u4E0E\u4EFF\u771F\u8FC7\u7A0B\u4EA4\u4E92

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

View File

@ -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 + ">");
}

View File

@ -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.

View File

@ -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));
}
}

View File

@ -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 <code>Message</code>s 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;
}
}

View File

@ -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;
}
}

View File

@ -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 <code>Message</code>s. When adding a
@ -116,6 +117,36 @@ public abstract class MessageSet<E extends Message> extends AbstractSet<E> 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<Message> getMessagesWithPriority(MessagePriority priority) {
List<Message> list = new ArrayList<>();
for (E m : messages) {
if (m.getPriority() == priority) {
list.add(m);
}
}
return list;
}
public void immute() {
mutable.immute();

View File

@ -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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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 <code>Warning</code> 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);
}

View File

@ -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 <code>Warning</code>s. 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<Warning> {
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<Warning> getCriticalWarnings() {
List<Message> list = getMessagesWithPriority(MessagePriority.HIGH);
return convertMessageListToWarningList(list);
}
public List<Warning> getNormalWarnings() {
List<Message> list = getMessagesWithPriority(MessagePriority.NORMAL);
return convertMessageListToWarningList(list);
}
public List<Warning> getInformativeWarnings() {
List<Message> list = getMessagesWithPriority(MessagePriority.LOW);
return convertMessageListToWarningList(list);
}
private static List<Warning> convertMessageListToWarningList(List<Message> list) {
List<Warning> warnings = new ArrayList<>(list.size());
for (Message m : list) {
warnings.add((Warning) m);
}
return warnings;
}
@Override
public WarningSet clone() {
try {

View File

@ -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);

View File

@ -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));
}

View File

@ -64,5 +64,8 @@ The following file format versions exist:
Rename <position> to <axialoffset> (<position> remains for backward compatibility)
Rename <rotation> to <angleoffset> (<rotation> 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.
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.

View File

@ -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"));
}

View File

@ -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));
}

View File

@ -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 <component>
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");

View File

@ -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("<html>---------- Bug report ----------\n");
sb.append('\n');
Color color = darkWarningColor;
Color color = darkErrorColor;
sb.append(String.format("<b style='color:rgb(%d, %d, %d)'>Please include a description about what actions you were " +
"performing when the exception occurred:</b>\n", color.getRed(), color.getGreen(), color.getBlue()));
sb.append("<i>(You can edit text directly in this window)</i>\n");

View File

@ -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<Error> 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;
}
}
}

View File

@ -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() {

View File

@ -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(
"<html>%s</html>", 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();
}
}

View File

@ -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

View File

@ -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(
"<html>%s</html>", 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();
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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 = "<html>";
tip = new StringBuilder("<html>");
if (includeSimName) {
tip += "<b>" + sim.getName() + "</b><br>";
}
switch (sim.getStatus()) {
case CANT_RUN:
tip += trans.get("simpanel.ttip.noData")+"<br>";
break;
case LOADED:
tip += trans.get("simpanel.ttip.loaded") + "<br>";
break;
case UPTODATE:
tip += trans.get("simpanel.ttip.uptodate") + "<br>";
break;
case OUTDATED:
tip += trans.get("simpanel.ttip.outdated") + "<br>";
break;
case EXTERNAL:
tip += trans.get("simpanel.ttip.external") + "<br>";
return tip;
case NOT_SIMULATED:
tip += trans.get("simpanel.ttip.notSimulated");
return tip;
tip.append("<b>").append(sim.getName()).append("</b><br>");
}
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("<br>");
break;
case LOADED:
tip.append(trans.get("simpanel.ttip.loaded")).append("<br>");
break;
case UPTODATE:
tip.append(trans.get("simpanel.ttip.uptodate")).append("<br>");
break;
case OUTDATED:
tip.append(trans.get("simpanel.ttip.outdated")).append("<br>");
break;
case EXTERNAL:
tip.append(trans.get("simpanel.ttip.external")).append("<br>");
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 += "<font color=\"red\"><i><b>" + trans.get("simpanel.ttip.simAbort") + ":</b></i> " +
((SimulationAbort)(abortEvent.getData())).toString() + "</font><br />";
if (abortEvent != null) {
tip.append("<font color=\"red\"><i><b>").append(trans.get("simpanel.ttip.simAbort")).append(":</b></i> ").append((abortEvent.getData()).toString()).append("</font><br />");
}
}
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 += "<br>" + 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("<html>");
if (includeSimName) {
tip.append("<b>").append(sim.getName()).append("</b>");
}
if (data == null) {
tip.append("<br>").append(trans.get("simpanel.ttip.noData"));
return tip.toString();
}
WarningSet warnings = data.getWarningSet();
if (warnings.isEmpty()) {
tip.append("<br>").append(ColorConversion.formatHTMLColor(dimTextColor, trans.get("simpanel.ttip.noWarnings")));
return tip.toString();
}
List<Warning> criticalWarnings = warnings.getCriticalWarnings();
List<Warning> normalWarnings = warnings.getNormalWarnings();
List<Warning> informativeWarnings = warnings.getInformativeWarnings();
// Critical warnings
if (!criticalWarnings.isEmpty()) {
tip.append("<br><b>")
.append(ColorConversion.formatHTMLColor(errorColor, trans.get("simpanel.ttip.criticalWarnings")))
.append("</b>");
for (Message m : criticalWarnings) {
tip.append("<br>").append(m.toString());
}
}
// Warnings
if (!normalWarnings.isEmpty()) {
tip.append("<br><b>")
.append(ColorConversion.formatHTMLColor(warningColor, trans.get("simpanel.ttip.normalWarnings")))
.append("</b>");
for (Message m : normalWarnings) {
tip.append("<br>").append(m.toString());
}
}
// Informative warnings
if (!informativeWarnings.isEmpty()) {
tip.append("<br><b>")
.append(ColorConversion.formatHTMLColor(informationColor, trans.get("simpanel.ttip.informativeWarnings")))
.append("</b>");
for (Message m : informativeWarnings) {
tip.append("<br>").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("<br>", "-").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")) {

View File

@ -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){

View File

@ -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<Simulation> 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);
}
}

View File

@ -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);
}
}

View File

@ -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 <sampo.niskanen@iki.fi>
*/
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();
}

View File

@ -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");
}
}

View File

@ -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<String> messages = new ArrayList<String>();
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);
}
}
}

View File

@ -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<Warning> criticalWarnings = warnings == null ? null : warnings.getCriticalWarnings();
List<Warning> normalWarnings = warnings == null ? null : warnings.getNormalWarnings();
List<Warning> 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<Warning> 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<Warning> 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) { }
}
}

View File

@ -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;
}

View File

@ -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("<font color=\"%s\">%s</font>", hexColor, content);
}
}

View File

@ -29,13 +29,17 @@ public class Icons {
*/
public static final Map<Simulation.Status, Icon> 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<Simulation.Status, Icon> map = new HashMap<Simulation.Status, Icon>();
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");

View File

@ -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

View File

@ -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");