Merge pull request #2561 from SiboVG/better-ca-comp-select

Use selectable component tree for CA plot/export components selection
This commit is contained in:
Sibo Van Gool 2024-09-22 08:45:19 +02:00 committed by GitHub
commit 803935fc06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 835 additions and 851 deletions

View File

@ -715,8 +715,6 @@ SimulationStepper.error.totalMassZero = Total mass of active states is 0
! SimulationExportPanel
SimExpPan.border.Vartoexport = Variables to export
SimExpPan.border.Stage = Stage to export
SimExpPan.but.Selectall = Select all
SimExpPan.but.Selectnone = Select none
SimExpPan.border.FormatSettings = Format settings
SimExpPan.lbl.Fieldsepstr = Field separator string:
SimExpPan.lbl.longA1 = <html>The string used to separate the fields in the exported file.<br>
@ -737,12 +735,17 @@ SimExpPan.lbl.ttip.Commentchar = The character(s) that mark a comment line.
SimExpPan.Fileexists.desc1 = File \"
SimExpPan.Fileexists.desc2 = \" exists. Overwrite?
SimExpPan.Fileexists.title = File exists
SimExpPan.ExportingVar.desc1 = Exporting 1 variable out of
SimExpPan.ExportingVar.desc2 = Exporting
SimExpPan.ExportingVar.desc3 = variables out of
SimExpPan.Col.Variable = Variable
SimExpPan.Col.Unit = Unit
! CSVExportPanel
CSVExportPanel.but.Selectall = Select all
CSVExportPanel.but.Selectnone = Select none
CSVExportPanel.ExportingVar.desc1 = Exporting 1 variable out of
CSVExportPanel.ExportingVar.desc2 = Exporting
CSVExportPanel.ExportingVar.desc3 = variables out of
CSVExportPanel.lbl.Export = Export
CSVExportPanel.lbl.Variable = Variable
CSVExportPanel.lbl.Unit = Unit
CSVExportPanel.lbl.Extra = Extra
CsvOptionPanel.separator.space = SPACE
CsvOptionPanel.separator.tab = TAB
@ -980,6 +983,7 @@ CAExportPanel.checkbox.ttip.Includecadesc = Include information at the beginning
CAExportPanel.dlg.MissingComponents.txt1 = The following data type(s) have no selected components and will be ignored during exporting:
CAExportPanel.dlg.MissingComponents.txt2 = Do you want to continue with the export?
CAExportPanel.dlg.MissingComponents.title = No components selected
CAExportPanel.btn.SelectComponents = Select components
! CADataTypeGroup
CADataTypeGroup.DOMAIN = Domain Parameter
@ -997,11 +1001,14 @@ CADomainDataType.lbl.rollrate = Roll rate
CAPlotConfiguration.TotalCD = <html>Total C<sub>D</sub> vs. Mach number</html>
! CAPlotTypeSelector
CAPlotTypeSelector.lbl.component = Component:
CAPlotTypeSelector.btn.SelectComponents = Select components
! CAPlotPanel
CAPlotPanel.lbl.PlotTitle = Component Analysis Plot
! ComponentSelectionDialog
ComponentSelectionDialog.btn.ConfirmSelection = Confirm selection
! Custom Material dialog
custmatdlg.title.Custommaterial = Custom material
custmatdlg.lbl.Materialname = Material name:

View File

@ -567,8 +567,8 @@ SimulationModifierTree.OptimizationParameters = معايير التحسين
! SimulationExportPanel
SimExpPan.border.Vartoexport = متغيرات للتصدير
SimExpPan.border.Stage = مرحلة التصدير
SimExpPan.but.Selectall = حدد الكل
SimExpPan.but.Selectnone = لا تختر شيء
CSVExportPanel.but.Selectall = حدد الكل
CSVExportPanel.but.Selectnone = لا تختر شيء
SimExpPan.border.FormatSettings = إعدادات التنسيق
SimExpPan.lbl.Fieldsepstr = :سلسلة فاصل المجال
SimExpPan.lbl.longA1 = <html>.السلسلة المستخدمة لفصل الحقول في الملف المصدر<br>
@ -589,11 +589,11 @@ SimExpPan.lbl.ttip.Commentchar = .الذي يميز سطر التعليق (ال
SimExpPan.Fileexists.desc1 = \" الملف
SimExpPan.Fileexists.desc2 = \" موجود. هل تريد الكتابة فوقه؟
SimExpPan.Fileexists.title = الملف موجود
SimExpPan.ExportingVar.desc1 = تصدير متغير واحد من
SimExpPan.ExportingVar.desc2 = تصدير
SimExpPan.ExportingVar.desc3 = المتغيرات من أصل
SimExpPan.Col.Variable = متغيرات
SimExpPan.Col.Unit = وحدة
CSVExportPanel.ExportingVar.desc1 = تصدير متغير واحد من
CSVExportPanel.ExportingVar.desc2 = تصدير
CSVExportPanel.ExportingVar.desc3 = المتغيرات من أصل
CSVExportPanel.lbl.Variable = متغيرات
CSVExportPanel.lbl.Unit = وحدة
CsvOptionPanel.separator.space = مفتاح المساحة

View File

@ -411,8 +411,8 @@ RK4SimulationStepper.error.valuesTooLarge = Hodnoty simulace prekrocily limity.
! SimulationExportPanel
SimExpPan.border.Vartoexport = Promenné k exportu
SimExpPan.but.Selectall = Oznac v\u0161e
SimExpPan.but.Selectnone = Nic neoznacuj
CSVExportPanel.but.Selectall = Oznac v\u0161e
CSVExportPanel.but.Selectnone = Nic neoznacuj
SimExpPan.border.Fieldsep = Oddelovac prvku
SimExpPan.lbl.Fieldsepstr = Retezec slou\u017Eící k oddelování prvku:
SimExpPan.lbl.longA1 = <html>Retezec slou\u017Eící k oddelení prvku v exportovaném souboru.<br>
@ -430,11 +430,11 @@ SimExpPan.but.Exporttofile = Exportuj do souboru...
SimExpPan.Fileexists.desc1 = Soubor \"
SimExpPan.Fileexists.desc2 = \" existuje. Chcete ho prepsat?
SimExpPan.Fileexists.title = Soubor existuje
SimExpPan.ExportingVar.desc1 = Exportuji 1 promennou od
SimExpPan.ExportingVar.desc2 = Exportuji
SimExpPan.ExportingVar.desc3 = promenné od
SimExpPan.Col.Variable = Promenná
SimExpPan.Col.Unit = Jednoty
CSVExportPanel.ExportingVar.desc1 = Exportuji 1 promennou od
CSVExportPanel.ExportingVar.desc2 = Exportuji
CSVExportPanel.ExportingVar.desc3 = promenné od
CSVExportPanel.lbl.Variable = Promenná
CSVExportPanel.lbl.Unit = Jednoty
CsvOptionPanel.separator.space = Mezerník

View File

@ -414,8 +414,8 @@ RK4SimulationStepper.error.valuesTooLarge = Simulationswerte
! SimulationExportPanel
SimExpPan.border.Vartoexport = zu exportierende Variablen
SimExpPan.but.Selectall = Alle auswählen
SimExpPan.but.Selectnone = Keine auswählen
CSVExportPanel.but.Selectall = Alle auswählen
CSVExportPanel.but.Selectnone = Keine auswählen
SimExpPan.border.Fieldsep = Feldtrennung
SimExpPan.lbl.Fieldsepstr = Trennzeichen
SimExpPan.lbl.longA1 = <html>Das Trennzeichen wird benutzt, um die Felder in der exportierten Datei voneinander zu trennen.<br>
@ -433,11 +433,11 @@ SimExpPan.but.Exporttofile = In Datei exportieren...
SimExpPan.Fileexists.desc1 = File \"",Datei \«"
SimExpPan.Fileexists.desc2 = \" existiert bereits. Überschreiben?"
SimExpPan.Fileexists.title = Datei existiert bereits
SimExpPan.ExportingVar.desc1 = Exportiere Variable 1 aus
SimExpPan.ExportingVar.desc2 = Exportiere
SimExpPan.ExportingVar.desc3 = Variablen aus
SimExpPan.Col.Variable = Variable
SimExpPan.Col.Unit = Einheit
CSVExportPanel.ExportingVar.desc1 = Exportiere Variable 1 aus
CSVExportPanel.ExportingVar.desc2 = Exportiere
CSVExportPanel.ExportingVar.desc3 = Variablen aus
CSVExportPanel.lbl.Variable = Variable
CSVExportPanel.lbl.Unit = Einheit
CsvOptionPanel.separator.space = LEER

View File

@ -969,11 +969,11 @@ ShockCordCfg.lbl.plus = Localizaci\u00f3n:
ShockCordCfg.tab.General = General
ShockCordCfg.tab.ttip.General = Propiedades generales
SimExpPan.Col.Unit = Unidad
SimExpPan.Col.Variable = Variable
SimExpPan.ExportingVar.desc1 = Exportar variables
SimExpPan.ExportingVar.desc2 = Exportar
SimExpPan.ExportingVar.desc3 = variables de
CSVExportPanel.lbl.Unit = Unidad
CSVExportPanel.lbl.Variable = Variable
CSVExportPanel.ExportingVar.desc1 = Exportar variables
CSVExportPanel.ExportingVar.desc2 = Exportar
CSVExportPanel.ExportingVar.desc3 = variables de
SimExpPan.Fileexists.desc1 = Archivo "
SimExpPan.Fileexists.desc2 = " ya existe. \u00bfDesea sobrescribirlo?
SimExpPan.Fileexists.title = El archivo ya existe
@ -982,8 +982,8 @@ SimExpPan.border.Fieldsep = Separador de campo
SimExpPan.border.Stage = Etapa a exportar
SimExpPan.border.Vartoexport = Variables para exportar
SimExpPan.but.Exporttofile = Exportar al documento ...
SimExpPan.but.Selectall = Seleccionar todo
SimExpPan.but.Selectnone = No seleccionar nada
CSVExportPanel.but.Selectall = Seleccionar todo
CSVExportPanel.but.Selectnone = No seleccionar nada
SimExpPan.checkbox.Incflightevents = Incluir los eventos del vuelo.
SimExpPan.checkbox.Includefielddesc = Incluir descripciones del campo.
SimExpPan.checkbox.Includesimudesc = Incluir descripci\u00f3n de la simulaci\u00f3n.

View File

@ -959,11 +959,11 @@ ShockCordCfg.lbl.plus = plus
ShockCordCfg.tab.General = G\u00E9n\u00E9ral
ShockCordCfg.tab.ttip.General = Propri\u00E9t\u00E9s g\u00E9n\u00E9rales
SimExpPan.Col.Unit = Unit\u00E9
SimExpPan.Col.Variable = Variable
SimExpPan.ExportingVar.desc1 = Exporter 1 variable sur un total de
SimExpPan.ExportingVar.desc2 = Exportation
SimExpPan.ExportingVar.desc3 = variable sur un total de
CSVExportPanel.lbl.Unit = Unit\u00E9
CSVExportPanel.lbl.Variable = Variable
CSVExportPanel.ExportingVar.desc1 = Exporter 1 variable sur un total de
CSVExportPanel.ExportingVar.desc2 = Exportation
CSVExportPanel.ExportingVar.desc3 = variable sur un total de
SimExpPan.Fileexists.desc1 = Le fichier "
SimExpPan.Fileexists.desc2 = " existe d\u00E9j\u00E0. Ecraser?
SimExpPan.Fileexists.title = Le fichier existe
@ -972,8 +972,8 @@ SimExpPan.border.Fieldsep = S\u00E9parateur de champ
SimExpPan.border.Stage = Etage \u00E0 exporter
SimExpPan.border.Vartoexport = Variables \u00E0 exporter
SimExpPan.but.Exporttofile = Exporter dans un fichier...
SimExpPan.but.Selectall = Tout s\u00E9lectionner
SimExpPan.but.Selectnone = Ne rien s\u00E9lectionner
CSVExportPanel.but.Selectall = Tout s\u00E9lectionner
CSVExportPanel.but.Selectnone = Ne rien s\u00E9lectionner
SimExpPan.checkbox.Incflightevents = Inclure les \u00E9v\u00E9nements de vol
SimExpPan.checkbox.Includefielddesc = Inclure les descriptions des champs
SimExpPan.checkbox.Includesimudesc = Inclure la description de la simulation

View File

@ -417,8 +417,8 @@ RK4SimulationStepper.error.valuesTooLarge = I valori di simulazione anno eccedut
! SimulationExportPanel
SimExpPan.border.Vartoexport = Variabili da esportare
SimExpPan.but.Selectall = Seleziona tutto
SimExpPan.but.Selectnone = Deseleziona tutto
CSVExportPanel.but.Selectall = Seleziona tutto
CSVExportPanel.but.Selectnone = Deseleziona tutto
SimExpPan.border.Fieldsep = Separatore di campo
SimExpPan.lbl.Fieldsepstr = Stringa di separatore di campo:
SimExpPan.lbl.longA1 = <html>La stringa usata per separare i campi nel file esportato.<br>
@ -436,11 +436,11 @@ SimExpPan.but.Exporttofile = Esporta nel file...
SimExpPan.Fileexists.desc1 = Il file \"
SimExpPan.Fileexists.desc2 = \" esiste. Sovrascrivo?
SimExpPan.Fileexists.title = Il file esiste
SimExpPan.ExportingVar.desc1 = Sto esportando 1 variabile su
SimExpPan.ExportingVar.desc2 = Sto esportando
SimExpPan.ExportingVar.desc3 = variabili su
SimExpPan.Col.Variable = Variabile
SimExpPan.Col.Unit = Unita'
CSVExportPanel.ExportingVar.desc1 = Sto esportando 1 variabile su
CSVExportPanel.ExportingVar.desc2 = Sto esportando
CSVExportPanel.ExportingVar.desc3 = variabili su
CSVExportPanel.lbl.Variable = Variabile
CSVExportPanel.lbl.Unit = Unita'
CsvOptionPanel.separator.space = SPAZIO

View File

@ -422,8 +422,8 @@ SimulationModifierTree.OptimizationParameters = \u6700\u9069\u5316\u30D1\u30E9\
! SimulationExportPanel
SimExpPan.border.Vartoexport = \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u3059\u308B\u5909\u6570
SimExpPan.but.Selectall = \u5168\u3066\u9078\u629E
SimExpPan.but.Selectnone = \u5168\u3066\u975E\u9078\u629E
CSVExportPanel.but.Selectall = \u5168\u3066\u9078\u629E
CSVExportPanel.but.Selectnone = \u5168\u3066\u975E\u9078\u629E
SimExpPan.border.Fieldsep = \u533A\u5207\u308A\u6587\u5B57
SimExpPan.lbl.Fieldsepstr = \u533A\u5207\u308A\u6587\u5B57\uFF1A
SimExpPan.lbl.longA1 = <html>\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u30D5\u30A1\u30A4\u30EB\u3067\u306E\u533A\u5207\u308A\u6587\u5B57<br>
@ -441,11 +441,11 @@ SimExpPan.but.Exporttofile = \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
SimExpPan.Fileexists.desc1 = \u30D5\u30A1\u30A4\u30EB \"
SimExpPan.Fileexists.desc2 = \" \u306F\u65E2\u306B\u5B58\u5728\u3057\u307E\u3059\u3002\u4E0A\u66F8\u304D\u3057\u307E\u3059\u304B\uFF1F
SimExpPan.Fileexists.title = \u30D5\u30A1\u30A4\u30EB\u306E\u4E0A\u66F8\u304D
SimExpPan.ExportingVar.desc1 = Exporting 1 variable out of
SimExpPan.ExportingVar.desc2 = \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
SimExpPan.ExportingVar.desc3 = \u5909\u6570\u3001\u5168\u4F53\u306E\u5909\u6570
SimExpPan.Col.Variable = \u5909\u6570
SimExpPan.Col.Unit = \u5358\u4F4D
CSVExportPanel.ExportingVar.desc1 = Exporting 1 variable out of
CSVExportPanel.ExportingVar.desc2 = \u30A8\u30AF\u30B9\u30DD\u30FC\u30C8
CSVExportPanel.ExportingVar.desc3 = \u5909\u6570\u3001\u5168\u4F53\u306E\u5909\u6570
CSVExportPanel.lbl.Variable = \u5909\u6570
CSVExportPanel.lbl.Unit = \u5358\u4F4D
CsvOptionPanel.separator.space = SPACE

View File

@ -541,8 +541,8 @@ SimulationModifierTree.OptimizationParameters = Optimalisatieparameters
! SimulationExportPanel
SimExpPan.border.Vartoexport = Variabelen om te exporteren
SimExpPan.border.Stage = Trap om te exporteren
SimExpPan.but.Selectall = Selecteer alles
SimExpPan.but.Selectnone = Selecteer niets
CSVExportPanel.but.Selectall = Selecteer alles
CSVExportPanel.but.Selectnone = Selecteer niets
SimExpPan.border.Fieldsep = Veldscheider
SimExpPan.lbl.Fieldsepstr = Veldscheidersteken:
SimExpPan.lbl.longA1 = <html>De tekenreeks die wordt gebruikt om de velden in het geëxporteerde bestand van elkaar te scheiden.<br>
@ -559,11 +559,11 @@ SimExpPan.lbl.ttip.Commentchar = Het teken of de tekens die een opmerkingregel m
SimExpPan.Fileexists.desc1 = Bestand \"
SimExpPan.Fileexists.desc2 = \" bestaat reeds. Overschrijven?
SimExpPan.Fileexists.title = Bestand bestaat reeds
SimExpPan.ExportingVar.desc1 = Exporteren van 1 variabele uit
SimExpPan.ExportingVar.desc2 = Exporteren
SimExpPan.ExportingVar.desc3 = variabelen uit
SimExpPan.Col.Variable = Variabele
SimExpPan.Col.Unit = Eenheid
CSVExportPanel.ExportingVar.desc1 = Exporteren van 1 variabele uit
CSVExportPanel.ExportingVar.desc2 = Exporteren
CSVExportPanel.ExportingVar.desc3 = variabelen uit
CSVExportPanel.lbl.Variable = Variabele
CSVExportPanel.lbl.Unit = Eenheid
CsvOptionPanel.separator.space = SPACE

View File

@ -414,8 +414,8 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
! SimulationExportPanel
SimExpPan.border.Vartoexport = Zmienne do wyeksportowania
SimExpPan.but.Selectall = Wybierz wszystko
SimExpPan.but.Selectnone = Odznacz wszystko
CSVExportPanel.but.Selectall = Wybierz wszystko
CSVExportPanel.but.Selectnone = Odznacz wszystko
SimExpPan.border.Fieldsep = Separator pól
SimExpPan.lbl.Fieldsepstr = Ci\u0105g znaków - separator pól:
SimExpPan.lbl.longA1 = <html>Ci\u0105g znaków stosowany do oddzielania pól w eksportowanym pliku.<br>
@ -433,11 +433,11 @@ update.dlg.latestVersion = Korzystasz z najnowszej wersji OpenRocket: %s.
SimExpPan.Fileexists.desc1 = Plik \"
SimExpPan.Fileexists.desc2 = \" istnieje. Nadpisa\u0107?
SimExpPan.Fileexists.title = Plik ju\u017C istnieje
SimExpPan.ExportingVar.desc1 = Eksportuj\u0119 1 zmienn\u0105 z
SimExpPan.ExportingVar.desc2 = Eksportuj\u0119
SimExpPan.ExportingVar.desc3 = zmienne z
SimExpPan.Col.Variable = Zmienna
SimExpPan.Col.Unit = Jednostka
CSVExportPanel.ExportingVar.desc1 = Eksportuj\u0119 1 zmienn\u0105 z
CSVExportPanel.ExportingVar.desc2 = Eksportuj\u0119
CSVExportPanel.ExportingVar.desc3 = zmienne z
CSVExportPanel.lbl.Variable = Zmienna
CSVExportPanel.lbl.Unit = Jednostka
CsvOptionPanel.separator.space = SPACJA

View File

@ -944,11 +944,11 @@ ShockCordCfg.lbl.plus = mais
ShockCordCfg.tab.General = Geral
ShockCordCfg.tab.ttip.General = Propriedades gerais
SimExpPan.Col.Unit = Unidade
SimExpPan.Col.Variable = Vari\u00e1vel
SimExpPan.ExportingVar.desc1 = Exportando uma vari\u00e1vel de
SimExpPan.ExportingVar.desc2 = Exportando
SimExpPan.ExportingVar.desc3 = vari\u00e1veis fora de
CSVExportPanel.lbl.Unit = Unidade
CSVExportPanel.lbl.Variable = Vari\u00e1vel
CSVExportPanel.ExportingVar.desc1 = Exportando uma vari\u00e1vel de
CSVExportPanel.ExportingVar.desc2 = Exportando
CSVExportPanel.ExportingVar.desc3 = vari\u00e1veis fora de
SimExpPan.Fileexists.desc1 = Arquivo "
SimExpPan.Fileexists.desc2 = " existe. Sobreescrever?
SimExpPan.Fileexists.title = Arquivo existe
@ -956,8 +956,8 @@ SimExpPan.border.Comments = Coment\u00e1rios
SimExpPan.border.Fieldsep = Separador de campo
SimExpPan.border.Vartoexport = Vari\u00e1veis para exportar
SimExpPan.but.Exporttofile = Exportar para arquivo...
SimExpPan.but.Selectall = Selecionar todos
SimExpPan.but.Selectnone = Limpar sele\u00e7\u00e3o
CSVExportPanel.but.Selectall = Selecionar todos
CSVExportPanel.but.Selectnone = Limpar sele\u00e7\u00e3o
SimExpPan.checkbox.Incflightevents = Incluir eventos de voo
SimExpPan.checkbox.Includefielddesc = Incluir descri\u00e7\u00f5es de campo
SimExpPan.checkbox.Includesimudesc = Incluir a descri\u00e7\u00e3o de simula\u00e7\u00e3o

View File

@ -555,8 +555,8 @@ SimulationModifierTree.OptimizationParameters = \u041E\u043F\u0442\u0438\u043C\u
! SimulationExportPanel
SimExpPan.border.Vartoexport = \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u043C\u044B\u0435 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435
SimExpPan.border.Stage = \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0442\u0443\u043F\u0435\u043D\u044C
SimExpPan.but.Selectall = \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435
SimExpPan.but.Selectnone = \u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440
CSVExportPanel.but.Selectall = \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435
CSVExportPanel.but.Selectnone = \u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u044B\u0431\u043E\u0440
SimExpPan.border.FormatSettings = \u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0444\u043E\u0440\u043C\u0430\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F
SimExpPan.lbl.Fieldsepstr = \u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u043F\u043E\u043B\u0435\u0439:
SimExpPan.lbl.longA1 = <html>\u0421\u0442\u0440\u043E\u043A\u0430, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u0430\u044F \u0434\u043B\u044F \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u0435\u0439 \u0432 \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u043C\u043E\u043C \u0444\u0430\u0439\u043B\u0435.<br>
@ -577,11 +577,11 @@ SimExpPan.lbl.ttip.Commentchar = \u0421\u0438\u043C\u0432\u043E\u043B(\u044B), \
SimExpPan.Fileexists.desc1 = \u0424\u0430\u0439\u043B \"
SimExpPan.Fileexists.desc2 = \" \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C?
SimExpPan.Fileexists.title = \u0424\u0430\u0439\u043B \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
SimExpPan.ExportingVar.desc1 = \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u043E\u0434\u043D\u0430 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F \u0438\u0437
SimExpPan.ExportingVar.desc2 = \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F
SimExpPan.ExportingVar.desc3 = \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u0438\u0437
SimExpPan.Col.Variable = \u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F
SimExpPan.Col.Unit = \u0415\u0434\u0438\u043D\u0438\u0446\u0430 \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F
CSVExportPanel.ExportingVar.desc1 = \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u043E\u0434\u043D\u0430 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F \u0438\u0437
CSVExportPanel.ExportingVar.desc2 = \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F
CSVExportPanel.ExportingVar.desc3 = \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u0438\u0437
CSVExportPanel.lbl.Variable = \u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F
CSVExportPanel.lbl.Unit = \u0415\u0434\u0438\u043D\u0438\u0446\u0430 \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F
CsvOptionPanel.separator.space = \u041F\u0440\u043E\u0431\u0435\u043B

View File

@ -682,8 +682,8 @@ SimulationStepper.error.totalMassZero = \u0417\u0430\u0433\u0430\u043b\u044c\u04
! SimulationExportPanel
SimExpPan.border.Vartoexport = \u0417\u043c\u0456\u043d\u043d\u0456 \u0434\u043b\u044f \u0435\u043a\u0441\u043f\u043e\u0440\u0442\u0443
SimExpPan.border.Stage = \u0415\u0442\u0430\u043f \u0434\u043b\u044f \u0435\u043a\u0441\u043f\u043e\u0440\u0442\u0443
SimExpPan.but.Selectall = \u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0432\u0441\u0435
SimExpPan.but.Selectnone = \u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438 \u0432\u0441\u0435
CSVExportPanel.but.Selectall = \u0412\u0438\u0431\u0440\u0430\u0442\u0438 \u0432\u0441\u0435
CSVExportPanel.but.Selectnone = \u0412\u0456\u0434\u043c\u0456\u043d\u0438\u0442\u0438 \u0432\u0441\u0435
SimExpPan.border.FormatSettings = \u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0443
SimExpPan.lbl.Fieldsepstr = \u0420\u044f\u0434\u043e\u043a \u0440\u043e\u0437\u0434\u0456\u043b\u044c\u043d\u0438\u043a\u0430 \u043f\u043e\u043b\u0456\u0432:
SimExpPan.lbl.longA1 = <html>\u0420\u044f\u0434\u043e\u043a, \u044f\u043a\u0438\u0439 \u0432\u0438\u043a\u043e\u0440\u0438\u0441\u0442\u043e\u0432\u0443\u0454\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0440\u043e\u0437\u0434\u0456\u043b\u0435\u043d\u043d\u044f \u043f\u043e\u043b\u0456\u0432 \u0443 \u0435\u043a\u0441\u043f\u043e\u0440\u0442\u043e\u0432\u0430\u043d\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0456.<br>
@ -704,11 +704,11 @@ SimExpPan.lbl.ttip.Commentchar = \u0421\u0438\u043c\u0432\u043e\u043b(\u0438), \
SimExpPan.Fileexists.desc1 = \u0424\u0430\u0439\u043b \"
SimExpPan.Fileexists.desc2 = \" \u0456\u0441\u043d\u0443\u0454. \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0430\u0442\u0438?
SimExpPan.Fileexists.title = \u0424\u0430\u0439\u043b \u0456\u0441\u043d\u0443\u0454
SimExpPan.ExportingVar.desc1 = \u0415\u043a\u0441\u043f\u043e\u0440\u0442 \u0437\u043c\u0456\u043d\u043d\u043e\u0457 1 \u0437
SimExpPan.ExportingVar.desc2 = \u0415\u043a\u0441\u043f\u043e\u0440\u0442
SimExpPan.ExportingVar.desc3 = \u0437\u043c\u0456\u043d\u043d\u0438\u0445 \u0437
SimExpPan.Col.Variable = \u0417\u043c\u0456\u043d\u043d\u0430
SimExpPan.Col.Unit = \u041e\u0434\u0438\u043d\u0438\u0446\u044f
CSVExportPanel.ExportingVar.desc1 = \u0415\u043a\u0441\u043f\u043e\u0440\u0442 \u0437\u043c\u0456\u043d\u043d\u043e\u0457 1 \u0437
CSVExportPanel.ExportingVar.desc2 = \u0415\u043a\u0441\u043f\u043e\u0440\u0442
CSVExportPanel.ExportingVar.desc3 = \u0437\u043c\u0456\u043d\u043d\u0438\u0445 \u0437
CSVExportPanel.lbl.Variable = \u0417\u043c\u0456\u043d\u043d\u0430
CSVExportPanel.lbl.Unit = \u041e\u0434\u0438\u043d\u0438\u0446\u044f
CsvOptionPanel.separator.space = \u041f\u0420\u041e\u0411\u0406\u041b
CsvOptionPanel.separator.tab = \u0412\u041a\u041b\u0410\u0414\u041a\u0410

View File

@ -1026,11 +1026,11 @@ ShockCordCfg.lbl.plus = \u52A0
ShockCordCfg.tab.General = \u5E38\u89C4
ShockCordCfg.tab.ttip.General = \u5E38\u89C4\u5C5E\u6027
SimExpPan.Col.Unit = \u5355\u4F4D
SimExpPan.Col.Variable = \u53D8\u91CF
SimExpPan.ExportingVar.desc1 = \u8F93\u51FA1\u4E2A\u53D8\u91CF\uFF0C\u5171\u8BA1
SimExpPan.ExportingVar.desc2 = \u8F93\u51FA
SimExpPan.ExportingVar.desc3 = \u4E2A\u53D8\u91CF, \u5171\u8BA1
CSVExportPanel.lbl.Unit = \u5355\u4F4D
CSVExportPanel.lbl.Variable = \u53D8\u91CF
CSVExportPanel.ExportingVar.desc1 = \u8F93\u51FA1\u4E2A\u53D8\u91CF\uFF0C\u5171\u8BA1
CSVExportPanel.ExportingVar.desc2 = \u8F93\u51FA
CSVExportPanel.ExportingVar.desc3 = \u4E2A\u53D8\u91CF, \u5171\u8BA1
SimExpPan.Fileexists.desc1 = \u6587\u4EF6 "
SimExpPan.Fileexists.desc2 = " \u5DF2\u5B58\u5728. \u8986\u76D6?
SimExpPan.Fileexists.title = \u6587\u4EF6\u5DF2\u5B58\u5728
@ -1038,8 +1038,8 @@ SimExpPan.border.Comments = \u6CE8\u91CA
SimExpPan.border.Fieldsep = \u6570\u636E\u5206\u9694\u7B26
SimExpPan.border.Stage = \u5BFC\u51FA\u706B\u7BAD\u7EA7
SimExpPan.border.Vartoexport = \u5BFC\u51FA\u53D8\u91CF
SimExpPan.but.Selectall = \u5168\u9009
SimExpPan.but.Selectnone = \u53D6\u6D88\u5168\u9009
CSVExportPanel.but.Selectall = \u5168\u9009
CSVExportPanel.but.Selectnone = \u53D6\u6D88\u5168\u9009
SimExpPan.checkbox.Incflightevents = \u98DE\u884C\u4E8B\u4EF6
SimExpPan.checkbox.Includefielddesc = \u6570\u636E\u57DF\u63CF\u8FF0
SimExpPan.checkbox.Includesimudesc = \u4EFF\u771F\u63CF\u8FF0

View File

@ -2,7 +2,6 @@ package info.openrocket.swing.gui.dialogs.componentanalysis;
import info.openrocket.core.componentanalysis.CADataBranch;
import info.openrocket.core.componentanalysis.CADataType;
import info.openrocket.core.l10n.Translator;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.core.startup.Application;
import info.openrocket.core.unit.Unit;
@ -13,75 +12,122 @@ import info.openrocket.swing.gui.util.SaveCSVWorker;
import info.openrocket.swing.gui.util.SwingPreferences;
import info.openrocket.swing.gui.widgets.CSVExportPanel;
import info.openrocket.swing.gui.widgets.SaveFileChooser;
import net.miginfocom.swing.MigLayout;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.awt.Color;
import javax.swing.UIManager;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.Dimension;
import java.awt.Font;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
public class CAExportPanel extends CSVExportPanel<CADataType> {
private static final long serialVersionUID = 4423905472892675964L;
private static final Translator trans = Application.getTranslator();
private static final int FIXED_COMPONENT_COLUMN_WIDTH = 500;
private static final SwingPreferences prefs = (SwingPreferences) Application.getPreferences();
private final ComponentAnalysisPlotExportPanel parent;
private final Map<CADataType, List<RocketComponent>> selectedComponents = new HashMap<>();
private List<JTextArea> selectedComponentsLabels;
private List<JScrollPane> selectedComponentsScrollPanes;
private static final int OPTION_COMPONENT_ANALYSIS_COMMENTS = 0;
private static final int OPTION_FIELD_DESCRIPTIONS = 1;
private final List<Map<RocketComponent, Boolean>> selectedComponents;
private final ComponentAnalysisPlotExportPanel parent;
private CAExportPanel(ComponentAnalysisPlotExportPanel parent, CADataType[] types,
boolean[] selected, CsvOptionPanel csvOptions, Component... extraComponents) {
super(types, selected, csvOptions, true, extraComponents);
public CAExportPanel(ComponentAnalysisPlotExportPanel parent, CADataType[] types, boolean[] selected) {
super(types, selected,
new CsvOptionPanel(CAExportPanel.class, true,
trans.get("CAExportPanel.checkbox.Includecadesc"),
trans.get("CAExportPanel.checkbox.ttip.Includecadesc"),
trans.get("SimExpPan.checkbox.Includefielddesc"),
trans.get("SimExpPan.checkbox.ttip.Includefielddesc")),
false);
this.parent = parent;
selectedComponents = new ArrayList<>(types.length);
Map<RocketComponent, Boolean> componentSelectedMap;
List<RocketComponent> components;
for (CADataType type : types) {
components = parent.getComponentsForType(type);
componentSelectedMap = new HashMap<>(components.size());
for (int i = 0; i < components.size(); i++) {
// Select the first component by default
componentSelectedMap.put(components.get(i), i == 0);
}
selectedComponents.add(componentSelectedMap);
// Initialize selected components map
for (int i = 0; i < types.length; i++) {
updateSelectedComponents(types[i], new ArrayList<>(), parent.getComponentsForType(types[i]),
selectedComponentsLabels.get(i), selectedComponentsScrollPanes.get(i));
}
}
// Set row heights dynamically
for (int row = 0; row < table.getRowCount(); row++) {
int numComponents = ((Map<?, ?>) table.getValueAt(row, 3)).size();
double correctNumComponents = Math.ceil(numComponents / 3.0); // 3 components per row
double height = Math.round(correctNumComponents * 25) + 10; // 25 pixels per component + 10 pixel margin
int rowHeight = Math.max(table.getRowHeight(), (int) height);
table.setRowHeight(row, rowHeight);
}
@Override
protected Component createExtraComponent(CADataType type, int index) {
JPanel panel = new JPanel(new MigLayout("ins 0, fill", "[grow]", "[][]"));
// Label for displaying selected components
JTextArea selectedComponentsLabel = new JTextArea();
selectedComponentsLabel.setEditable(false);
selectedComponentsLabel.setWrapStyleWord(true);
selectedComponentsLabel.setLineWrap(true);
selectedComponentsLabel.setOpaque(false);
selectedComponentsLabel.setFont(UIManager.getFont("Label.font").deriveFont(Font.PLAIN, prefs.getUIFontSize() - 1));
JScrollPane scrollPane = new JScrollPane(selectedComponentsLabel);
scrollPane.setPreferredSize(new Dimension(200, 50)); // Adjust as needed
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
panel.add(scrollPane, "growx, wrap");
selectedComponentsLabels = selectedComponentsLabels != null ? selectedComponentsLabels : new ArrayList<>();
selectedComponentsScrollPanes = selectedComponentsScrollPanes != null ? selectedComponentsScrollPanes : new ArrayList<>();
selectedComponentsLabels.add(selectedComponentsLabel);
selectedComponentsScrollPanes.add(scrollPane);
// Select components button
JButton selectComponentsBtn = new JButton(trans.get("CAExportPanel.btn.SelectComponents"));
panel.add(selectComponentsBtn, "growx, wrap");
selectComponentsBtn.addActionListener(e -> {
List<RocketComponent> availableComponents = parent.getComponentsForType(type);
ComponentSelectionDialog dialog = new ComponentSelectionDialog(
SwingUtilities.getWindowAncestor(this),
parent.getDocument(),
availableComponents,
selectedComponents.get(type)
);
List<RocketComponent> newSelectedComponents = dialog.showDialog();
updateSelectedComponents(type, newSelectedComponents, availableComponents, selectedComponentsLabel, scrollPane);
});
return panel;
}
@Override
protected String getExtraColumnLabelKey() {
return "CAExportPanel.Col.Components";
}
private void updateSelectedComponents(CADataType type, List<RocketComponent> components,
List<RocketComponent> componentsForType, JTextArea label,
JScrollPane scrollPane) {
components = (components != null && !components.isEmpty()) ? components : componentsForType.subList(0, 1);
List<RocketComponent> selectedComponentsList = this.selectedComponents.computeIfAbsent(type, k -> new ArrayList<>());
selectedComponentsList.clear();
selectedComponentsList.addAll(components);
updateSelectedComponentsLabel(label, scrollPane, components);
}
private void updateSelectedComponentsLabel(JTextArea label, JScrollPane scrollPane, List<RocketComponent> components) {
String componentNames = components.stream()
.map(RocketComponent::getName)
.reduce((a, b) -> a + ", " + b)
.orElse("");
label.setText(componentNames);
label.setToolTipText(componentNames); // Add tooltip in case the text is too long
scrollPane.revalidate();
scrollPane.repaint();
}
public static CAExportPanel create(ComponentAnalysisPlotExportPanel parent, CADataType[] types) {
@ -90,39 +136,7 @@ public class CAExportPanel extends CSVExportPanel<CADataType> {
selected[i] = ((SwingPreferences) Application.getPreferences()).isComponentAnalysisDataTypeExportSelected(types[i]);
}
CsvOptionPanel csvOptions = new CsvOptionPanel(CAExportPanel.class, false,
trans.get("CAExportPanel.checkbox.Includecadesc"),
trans.get("CAExportPanel.checkbox.ttip.Includecadesc"),
trans.get("SimExpPan.checkbox.Includefielddesc"),
trans.get("SimExpPan.checkbox.ttip.Includefielddesc"));
return new CAExportPanel(parent, types, selected, csvOptions);
}
protected void initializeTable(CADataType[] types) {
super.initializeTable(types);
// Set custom renderers for each column
TableColumn firstColumn = table.getColumnModel().getColumn(0);
firstColumn.setCellRenderer(new CheckBoxRenderer());
firstColumn.setCellEditor(new CheckBoxEditor());
table.getColumnModel().getColumn(1).setCellRenderer(new LeftAlignedRenderer());
table.getColumnModel().getColumn(2).setCellRenderer(new LeftAlignedRenderer());
ComponentCheckBoxPanel.ComponentSelectionListener listener = (newStates) -> {
int row = table.getSelectedRow();
if (row != -1) {
selectedComponents.set(row, newStates);
}
};
TableColumn componentColumn = table.getColumnModel().getColumn(3);
componentColumn.setCellRenderer(new ComponentCheckBoxRenderer(listener));
componentColumn.setCellEditor(new ComponentCheckBoxEditor(listener));
componentColumn.setPreferredWidth(FIXED_COMPONENT_COLUMN_WIDTH);
// Set specific client properties for FlatLaf
table.setShowHorizontalLines(true);
return new CAExportPanel(parent, types, selected);
}
@Override
@ -133,7 +147,7 @@ public class CAExportPanel extends CSVExportPanel<CADataType> {
List<CADataType> typesWithNoComponents = new ArrayList<>();
for (int i = 0; i < selected.length; i++) {
if (selected[i]) {
boolean hasSelectedComponent = selectedComponents.get(i).values().stream().anyMatch(v -> v);
boolean hasSelectedComponent = !selectedComponents.get(i).isEmpty();
if (!hasSelectedComponent) {
typesWithNoComponents.add(types[i]);
}
@ -188,12 +202,9 @@ public class CAExportPanel extends CSVExportPanel<CADataType> {
csvOptions.storePreferences();
// Store preferences and export
int n = 0;
((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
for (int i = 0; i < selected.length; i++) {
((SwingPreferences) Application.getPreferences()).setComponentAnalysisExportSelected(types[i], selected[i]);
if (selected[i])
n++;
}
List<CADataType> fieldTypes = new ArrayList<>();
@ -203,12 +214,7 @@ public class CAExportPanel extends CSVExportPanel<CADataType> {
// Iterate through the table to get selected items
for (int i = 0; i < selected.length; i++) {
if (selected[i]) {
List<RocketComponent> selectedComponentsList = new ArrayList<>();
for (Map.Entry<RocketComponent, Boolean> entry : selectedComponents.get(i).entrySet()) {
if (entry.getValue()) {
selectedComponentsList.add(entry.getKey());
}
}
List<RocketComponent> selectedComponentsList = new ArrayList<>(selectedComponents.get(i));
if (!selectedComponentsList.isEmpty()) {
fieldTypes.add(types[i]);
fieldUnits.add(units[i]);
@ -232,315 +238,4 @@ public class CAExportPanel extends CSVExportPanel<CADataType> {
return true;
}
@Override
protected CSVExportPanel<CADataType>.SelectionTableModel createTableModel() {
return new CASelectionTableModel();
}
protected class CASelectionTableModel extends SelectionTableModel {
private static final int COMPONENTS = 3;
@Override
public int getColumnCount() {
return 4;
}
@Override
public String getColumnName(int column) {
//// Components
if (column == COMPONENTS) {
return trans.get("CAExportPanel.Col.Components");
}
return super.getColumnName(column);
}
@Override
public Class<?> getColumnClass(int column) {
//// Components
if (column == COMPONENTS) {
return Map.class;
}
return super.getColumnClass(column);
}
@Override
public Object getValueAt(int row, int column) {
if (column == COMPONENTS) {
return selectedComponents.get(row);
}
return super.getValueAt(row, column);
}
@Override
public void setValueAt(Object value, int row, int column) {
if (column == COMPONENTS) {
selectedComponents.set(row, (Map<RocketComponent, Boolean>) value);
fireTableCellUpdated(row, column);
} else {
super.setValueAt(value, row, column);
}
}
@Override
public boolean isCellEditable(int row, int column) {
if (column == COMPONENTS) {
return true;
}
return super.isCellEditable(row, column);
}
}
private static class CheckBoxRenderer extends JCheckBox implements TableCellRenderer {
public CheckBoxRenderer() {
setHorizontalAlignment(JLabel.CENTER);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
setSelected((Boolean) value);
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); // Add top padding
setVerticalAlignment(JLabel.TOP);
return this;
}
}
private static class CheckBoxEditor extends DefaultCellEditor {
public CheckBoxEditor() {
super(new JCheckBox());
((JCheckBox)getComponent()).setHorizontalAlignment(JLabel.CENTER);
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
Component c = super.getTableCellEditorComponent(table, value, isSelected, row, column);
if (c instanceof JCheckBox) {
JCheckBox cb = (JCheckBox) c;
cb.setVerticalAlignment(JLabel.TOP);
cb.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
}
return c;
}
}
private static class LeftAlignedRenderer extends DefaultTableCellRenderer {
public LeftAlignedRenderer() {
setHorizontalAlignment(JLabel.LEFT);
setVerticalAlignment(JLabel.TOP);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
c.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
c.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
((JComponent) c).setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0)); // Add top and left padding
return c;
}
}
private static class ComponentCheckBoxRenderer implements TableCellRenderer {
private ComponentCheckBoxPanel panel;
private final ComponentCheckBoxPanel.ComponentSelectionListener listener;
public ComponentCheckBoxRenderer(ComponentCheckBoxPanel.ComponentSelectionListener listener) {
this.listener = listener;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (!(value instanceof Map)) {
JLabel errorLabel = new JLabel("Invalid data");
errorLabel.setForeground(Color.RED);
return errorLabel;
}
@SuppressWarnings("unchecked")
Map<RocketComponent, Boolean> componentMap = (Map<RocketComponent, Boolean>) value;
if (panel == null) {
panel = new ComponentCheckBoxPanel(componentMap);
panel.setComponentSelectionListener(listener);
} else {
panel.updateComponentStates(componentMap);
}
panel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
panel.setGridColor(table.getGridColor());
panel.setSelected(isSelected);
return panel;
}
}
private static class ComponentCheckBoxPanel extends JPanel {
private final Map<RocketComponent, JCheckBox> checkBoxMap = new HashMap<>();
private final AtomicBoolean updatingState = new AtomicBoolean(false);
private Color gridColor = Color.GRAY;
private boolean isSelected = false;
public ComponentCheckBoxPanel(Map<RocketComponent, Boolean> componentMap) {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1.0;
gbc.insets = new Insets(2, 2, 2, 2);
createCheckBoxes(componentMap, gbc);
// Add an empty component to push everything to the top-left
gbc.gridx = 0;
gbc.gridy = (componentMap.size() + 2) / 3 + 1;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
add(new JPanel(), gbc);
// Ensure at least one checkbox is selected
if (checkBoxMap.values().stream().noneMatch(JCheckBox::isSelected) && !checkBoxMap.isEmpty()) {
checkBoxMap.values().iterator().next().setSelected(true);
}
}
private void createCheckBoxes(Map<RocketComponent, Boolean> componentMap, GridBagConstraints gbc) {
int row = 0;
int col = 0;
for (Map.Entry<RocketComponent, Boolean> entry : componentMap.entrySet()) {
RocketComponent component = entry.getKey();
Boolean isSelected = entry.getValue();
// Skip null components
if (component == null) {
continue;
}
String componentName = component.getName();
// Use a default name if getName() returns null
if (componentName == null) {
componentName = "Unnamed Component";
}
JCheckBox checkBox = new JCheckBox(componentName, isSelected != null && isSelected);
checkBox.setOpaque(false);
checkBox.setMargin(new Insets(0, 0, 0, 0));
checkBox.addItemListener(checkBoxListener);
checkBoxMap.put(component, checkBox);
gbc.gridx = col;
gbc.gridy = row;
add(checkBox, gbc);
col++;
if (col > 2) {
col = 0;
row++;
}
}
}
public void updateComponentStates(Map<RocketComponent, Boolean> newStates) {
updatingState.set(true);
try {
for (Map.Entry<RocketComponent, Boolean> entry : newStates.entrySet()) {
JCheckBox checkBox = checkBoxMap.get(entry.getKey());
if (checkBox != null) {
checkBox.setSelected(entry.getValue());
}
}
} finally {
updatingState.set(false);
}
}
public Map<RocketComponent, Boolean> getComponentStates() {
return checkBoxMap.entrySet().stream()
.collect(HashMap::new,
(m, e) -> m.put(e.getKey(), e.getValue().isSelected()),
HashMap::putAll);
}
public void setGridColor(Color color) {
this.gridColor = color;
}
public void setSelected(boolean selected) {
this.isSelected = selected;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw the bottom border
g.setColor(gridColor);
g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1);
// If selected, draw a slight highlight
if (isSelected) {
g.setColor(new Color(0, 0, 255, 30)); // Semi-transparent blue
g.fillRect(0, 0, getWidth(), getHeight() - 1);
}
}
public interface ComponentSelectionListener {
void onComponentSelectionChanged(Map<RocketComponent, Boolean> newStates);
}
private ComponentSelectionListener listener;
public void setComponentSelectionListener(ComponentSelectionListener listener) {
this.listener = listener;
}
private final ItemListener checkBoxListener = e -> {
if (updatingState.get()) return;
// Remove the check for deselection and forced selection
if (listener != null) {
listener.onComponentSelectionChanged(getComponentStates());
}
// Notify the table that the value has changed
firePropertyChange("value", null, getComponentStates());
};
}
private static class ComponentCheckBoxEditor extends AbstractCellEditor implements TableCellEditor {
private ComponentCheckBoxPanel panel;
private final ComponentCheckBoxPanel.ComponentSelectionListener listener;
public ComponentCheckBoxEditor(ComponentCheckBoxPanel.ComponentSelectionListener listener) {
this.listener = listener;
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if (!(value instanceof Map)) {
// Return a default component if value is not a Map
JLabel errorLabel = new JLabel("Invalid data");
errorLabel.setForeground(Color.RED);
return errorLabel;
}
@SuppressWarnings("unchecked")
Map<RocketComponent, Boolean> componentMap = (Map<RocketComponent, Boolean>) value;
if (panel == null) {
panel = new ComponentCheckBoxPanel(componentMap);
panel.setComponentSelectionListener(listener);
} else {
panel.updateComponentStates(componentMap);
}
panel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
return panel;
}
@Override
public Object getCellEditorValue() {
return panel.getComponentStates();
}
}
}

View File

@ -2,11 +2,12 @@ package info.openrocket.swing.gui.dialogs.componentanalysis;
import info.openrocket.core.componentanalysis.CADataBranch;
import info.openrocket.core.componentanalysis.CADataType;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.core.unit.Unit;
import info.openrocket.swing.gui.plot.Plot;
import org.jfree.data.xy.XYSeries;
import java.util.Collections;
import java.util.ArrayList;
import java.util.List;
public class CAPlot extends Plot<CADataType, CADataBranch, CAPlotConfiguration> {
@ -18,12 +19,27 @@ public class CAPlot extends Plot<CADataType, CADataBranch, CAPlotConfiguration>
@Override
protected List<XYSeries> createSeriesForType(int dataIndex, int startIndex, CADataType type, Unit unit,
CADataBranch branch, int branchIdx, String branchName, String baseName) {
// Default implementation for regular DataBranch
MetadataXYSeries series = new MetadataXYSeries(startIndex, false, true, branchIdx, unit.getUnit(),
branchName, baseName);
// Get the component info
List<RocketComponent> components = filledConfig.getComponents(dataIndex);
List<String> componentNames = filledConfig.getComponentNames(dataIndex);
// Get the component name
String componentName = filledConfig.getComponentName(dataIndex);
// Create the series for each component
List<XYSeries> allSeries = new ArrayList<>();
for (int i = 0; i < components.size(); i++) {
XYSeries series = createSingleSeries(startIndex*1000 + i, type, unit, branch, branchIdx, branchName, baseName,
components.get(i), componentNames.get(i));
allSeries.add(series);
}
return allSeries;
}
private XYSeries createSingleSeries(int key, CADataType type, Unit unit,
CADataBranch branch, int branchIdx, String branchName, String baseName,
RocketComponent component, String componentName) {
// Default implementation for regular DataBranch
MetadataXYSeries series = new MetadataXYSeries(key, false, true, branchIdx, unit.getUnit(),
branchName, baseName);
// Create a new description that includes the component name
String newBaseName = baseName;
@ -34,7 +50,7 @@ public class CAPlot extends Plot<CADataType, CADataBranch, CAPlotConfiguration>
series.updateDescription();
List<Double> plotx = branch.get(filledConfig.getDomainAxisType());
List<Double> ploty = branch.get(type, filledConfig.getComponent(dataIndex));
List<Double> ploty = branch.get(type, component);
int pointCount = plotx.size();
for (int j = 0; j < pointCount; j++) {
@ -43,6 +59,6 @@ public class CAPlot extends Plot<CADataType, CADataBranch, CAPlotConfiguration>
series.add(x, y);
}
return Collections.singletonList(series);
return series;
}
}

View File

@ -7,21 +7,21 @@ import info.openrocket.core.l10n.Translator;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.core.startup.Application;
import info.openrocket.core.unit.Unit;
import info.openrocket.core.util.ArrayList;
import info.openrocket.swing.gui.plot.Axis;
import info.openrocket.swing.gui.plot.PlotConfiguration;
import java.util.ArrayList;
import java.util.List;
public class CAPlotConfiguration extends PlotConfiguration<CADataType, CADataBranch> {
private static final Translator trans = Application.getTranslator();
private ArrayList<RocketComponent> plotDataComponents = new ArrayList<>();
private List<List<RocketComponent>> plotDataComponents = new ArrayList<>();
public static final CAPlotConfiguration[] DEFAULT_CONFIGURATIONS;
static {
ArrayList<CAPlotConfiguration> configs = new ArrayList<>();
List<CAPlotConfiguration> configs = new ArrayList<>();
CAPlotConfiguration config;
//// Total CD vs Mach
@ -53,17 +53,21 @@ public class CAPlotConfiguration extends PlotConfiguration<CADataType, CADataBra
plotDataComponents.add(null);
}
public RocketComponent getComponent(int index) {
public List<RocketComponent> getComponents(int index) {
return plotDataComponents.get(index);
}
public void setPlotDataComponent(int index, RocketComponent component) {
plotDataComponents.set(index, component);
public void setPlotDataComponents(int index, List<RocketComponent> components) {
plotDataComponents.set(index, components);
}
public String getComponentName(int dataIndex) {
RocketComponent component = getComponent(dataIndex);
return component != null ? component.getName() : "";
public List<String> getComponentNames(int dataIndex) {
List<RocketComponent> components = getComponents(dataIndex);
List<String> names = new ArrayList<>(components.size());
for (RocketComponent c : components) {
names.add(c != null ? c.getName() : "");
}
return names;
}
@Override
@ -78,8 +82,12 @@ public class CAPlotConfiguration extends PlotConfiguration<CADataType, CADataBra
}
Axis axis = allAxes.get(index);
double min = unit.toUnit(data.get(0).getMinimum(type, getComponent(i)));
double max = unit.toUnit(data.get(0).getMaximum(type, getComponent(i)));
double min = Double.MAX_VALUE;
double max = Double.MIN_VALUE;
for (RocketComponent c : getComponents(i)) {
min = Math.min(min, unit.toUnit(data.get(0).getMinimum(type, c)));
max = Math.max(max, unit.toUnit(data.get(0).getMaximum(type, c)));
}
for (int j = 1; j < data.size(); j++) {
// Ignore empty data
@ -98,7 +106,10 @@ public class CAPlotConfiguration extends PlotConfiguration<CADataType, CADataBra
@SuppressWarnings("unchecked")
public CAPlotConfiguration cloneConfiguration() {
CAPlotConfiguration clone = super.cloneConfiguration();
clone.plotDataComponents = this.plotDataComponents.clone();
clone.plotDataComponents = new ArrayList<>(plotDataComponents.size());
for (List<RocketComponent> components : plotDataComponents) {
clone.plotDataComponents.add(components != null ? new ArrayList<>(components) : null);
}
return clone;
}
}

View File

@ -4,7 +4,6 @@ import info.openrocket.core.componentanalysis.CADataBranch;
import info.openrocket.core.componentanalysis.CADataType;
import info.openrocket.core.componentanalysis.CADataTypeGroup;
import info.openrocket.core.componentanalysis.CADomainDataType;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.core.unit.Unit;
import info.openrocket.swing.gui.plot.PlotPanel;
@ -38,8 +37,7 @@ public class CAPlotPanel extends PlotPanel<CADataType, CADataBranch, CADataTypeG
PRESET_ARRAY[PRESET_ARRAY.length - 1] = CUSTOM_CONFIGURATION;
}
private CAPlotPanel(ComponentAnalysisPlotExportPanel parent,
CADomainDataType[] typesX, CADataType[] typesY) {
private CAPlotPanel(ComponentAnalysisPlotExportPanel parent, CADomainDataType[] typesX, CADataType[] typesY) {
super(typesX, typesY, CUSTOM_CONFIGURATION, PRESET_ARRAY, DEFAULT_CONFIGURATION, null, null);
this.parent = parent;
@ -63,15 +61,14 @@ public class CAPlotPanel extends PlotPanel<CADataType, CADataBranch, CADataTypeG
selector.addComponentSelectionListener(e -> {
if (modifying > 0) return;
RocketComponent component = selector.getSelectedComponent();
configuration.setPlotDataComponent(idx, component);
configuration.setPlotDataComponents(idx, selector.getSelectedComponents());
});
}
@Override
protected CAPlotTypeSelector createSelector(int i, CADataType type, Unit unit, int axis) {
return new CAPlotTypeSelector(parent, i, type, unit, axis, List.of(typesY),
parent.getComponentsForType(type), configuration, configuration.getComponent(i));
return new CAPlotTypeSelector(parent, parent.getDocument(), i, type, unit, axis, List.of(typesY),
parent.getComponentsForType(type), configuration, configuration.getComponents(i));
}
public void setXAxis(CADomainDataType type) {

View File

@ -2,39 +2,79 @@ package info.openrocket.swing.gui.dialogs.componentanalysis;
import info.openrocket.core.componentanalysis.CADataType;
import info.openrocket.core.componentanalysis.CADataTypeGroup;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.core.startup.Application;
import info.openrocket.core.unit.Unit;
import info.openrocket.core.util.StringUtils;
import info.openrocket.swing.gui.plot.PlotTypeSelector;
import info.openrocket.swing.gui.util.SwingPreferences;
import net.miginfocom.swing.MigLayout;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.UIManager;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
public class CAPlotTypeSelector extends PlotTypeSelector<CADataType, CADataTypeGroup> {
private final JComboBox<RocketComponent> componentSelector;
private static final SwingPreferences prefs = (SwingPreferences) Application.getPreferences();
public CAPlotTypeSelector(final ComponentAnalysisPlotExportPanel parent, int plotIndex,
CADataType type, Unit unit, int position, List<CADataType> availableTypes,
private final JTextArea selectedComponentsLabel;
private final JScrollPane selectedComponentsScrollPane;
private final List<RocketComponent> selectedComponents = new ArrayList<>();
private List<RocketComponent> componentsForType;
private final List<ComponentSelectionListener> componentSelectionListeners = new ArrayList<>();
public CAPlotTypeSelector(final ComponentAnalysisPlotExportPanel parent, OpenRocketDocument document,
int plotIndex, CADataType type, Unit unit, int position, List<CADataType> availableTypes,
List<RocketComponent> componentsForType, CAPlotConfiguration configuration,
RocketComponent selectedComponent) {
List<RocketComponent> initialSelectedComponents) {
super(plotIndex, type, unit, position, availableTypes, false);
if (componentsForType.isEmpty()) {
throw new IllegalArgumentException("No components for type " + type);
}
// Selected components label
selectedComponentsLabel = new JTextArea();
selectedComponentsLabel.setEditable(false);
selectedComponentsLabel.setWrapStyleWord(true);
selectedComponentsLabel.setLineWrap(true);
selectedComponentsLabel.setOpaque(false);
selectedComponentsLabel.setFont(UIManager.getFont("Label.font").deriveFont(Font.PLAIN, prefs.getUIFontSize() - 1));
selectedComponentsScrollPane = new JScrollPane(selectedComponentsLabel);
selectedComponentsScrollPane.setPreferredSize(new Dimension(200, 60)); // Adjust as needed
selectedComponentsScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
// Update the data
setComponentsForType(type, componentsForType);
updateSelectedComponents(initialSelectedComponents, componentsForType, configuration, plotIndex);
// Component selector
selectedComponent = selectedComponent != null ? selectedComponent : componentsForType.get(0);
this.add(new JLabel(trans.get("CAPlotTypeSelector.lbl.component")));
componentSelector = new JComboBox<>(componentsForType.toArray(new RocketComponent[0]));
componentSelector.setSelectedItem(selectedComponent);
configuration.setPlotDataComponent(plotIndex, selectedComponent);
this.add(componentSelector, "growx, gapright para");
final JPanel componentSelectorPanel = new JPanel(new MigLayout("ins 0"));
JButton selectComponentButton = new JButton(trans.get("CAPlotTypeSelector.btn.SelectComponents"));
selectComponentButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ComponentSelectionDialog dialog = new ComponentSelectionDialog(parent.getParentWindow(), document,
CAPlotTypeSelector.this.componentsForType, CAPlotTypeSelector.this.selectedComponents);
List<RocketComponent> selectedComponents = dialog.showDialog();
if (selectedComponents != null) {
updateSelectedComponents(selectedComponents, CAPlotTypeSelector.this.componentsForType,
configuration, plotIndex);
}
}
});
componentSelectorPanel.add(selectComponentButton, "spanx, wrap");
componentSelectorPanel.add(selectedComponentsScrollPane, "wrap");
this.add(componentSelectorPanel, "growx, gapleft para, gapright para");
// Remove button
addRemoveButton();
typeSelector.addActionListener(new ActionListener() {
@ -42,32 +82,65 @@ public class CAPlotTypeSelector extends PlotTypeSelector<CADataType, CADataTypeG
public void actionPerformed(ActionEvent e) {
CADataType type = (CADataType) typeSelector.getSelectedItem();
List<RocketComponent> componentsForType = parent.getComponentsForType(type);
componentSelector.removeAllItems();
for (RocketComponent component : componentsForType) {
componentSelector.addItem(component);
}
componentSelector.setSelectedIndex(0);
configuration.setPlotDataComponent(plotIndex, (RocketComponent) componentSelector.getSelectedItem());
setComponentsForType(type, componentsForType);
updateSelectedComponents(null, componentsForType, configuration, plotIndex);
}
});
}
public CAPlotTypeSelector(final ComponentAnalysisPlotExportPanel parent, int plotIndex,
CADataType type, Unit unit, int position, List<CADataType> availableTypes,
List<RocketComponent> componentsForType, CAPlotConfiguration configuration) {
this(parent, plotIndex, type, unit, position, availableTypes, componentsForType, configuration, null);
private void setComponentsForType(CADataType type, List<RocketComponent> componentsForType) {
if (componentsForType.isEmpty()) {
throw new IllegalArgumentException("No components for type " + type);
}
this.componentsForType = componentsForType;
}
public void addComponentSelectionListener(ItemListener listener) {
componentSelector.addItemListener(listener);
private void updateSelectedComponents(List<RocketComponent> components, List<RocketComponent> componentsForType,
CAPlotConfiguration configuration, int plotIndex) {
components = (components != null && !components.isEmpty()) ? components : componentsForType.subList(0, 1);
this.selectedComponents.clear();
this.selectedComponents.addAll(components);
updateSelectedComponentsLabel(this.selectedComponents);
configuration.setPlotDataComponents(plotIndex, this.selectedComponents);
notifyComponentSelectionListeners();
}
public RocketComponent getSelectedComponent() {
return (RocketComponent) componentSelector.getSelectedItem();
private void updateSelectedComponentsLabel(List<RocketComponent> components) {
List<String> names = new ArrayList<>(components.size());
for (RocketComponent c : components) {
names.add(c.getName());
}
selectedComponentsLabel.setText(StringUtils.join(", ", names));
selectedComponentsLabel.setToolTipText(StringUtils.join(", ", names)); // Add tooltip in case the text is too long
selectedComponentsScrollPane.revalidate();
selectedComponentsScrollPane.repaint();
}
public void addComponentSelectionListener(ComponentSelectionListener listener) {
componentSelectionListeners.add(listener);
}
public void removeComponentSelectionListener(ComponentSelectionListener listener) {
componentSelectionListeners.remove(listener);
}
private void notifyComponentSelectionListeners() {
for (ComponentSelectionListener listener : this.componentSelectionListeners) {
listener.componentsSelected(this.selectedComponents);
}
}
public List<RocketComponent> getSelectedComponents() {
return this.selectedComponents;
}
@Override
protected String getDisplayString(CADataType item) {
return StringUtils.removeHTMLTags(item.getName());
}
public interface ComponentSelectionListener {
void componentsSelected(List<RocketComponent> selectedComponents);
}
}

View File

@ -1,5 +1,6 @@
package info.openrocket.swing.gui.dialogs.componentanalysis;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.l10n.Translator;
import info.openrocket.core.startup.Application;
@ -28,7 +29,7 @@ public class ComponentAnalysisDialog extends JDialog {
private JButton okButton;
public ComponentAnalysisDialog(RocketPanel rocketPanel) {
public ComponentAnalysisDialog(OpenRocketDocument document, RocketPanel rocketPanel) {
//// Component analysis
super(SwingUtilities.getWindowAncestor(rocketPanel), trans.get("ComponentAnalysisDialog.componentanalysis"));
@ -42,8 +43,8 @@ public class ComponentAnalysisDialog extends JDialog {
tabbedPane.addTab(trans.get("ComponentAnalysisDialog.tab.General"), generalTab);
// Plot export tab
ComponentAnalysisPlotExportPanel plotExportTab = new ComponentAnalysisPlotExportPanel(this, generalTab.getParameters(),
generalTab.getAerodynamicCalculator(), generalTab.getRocket());
ComponentAnalysisPlotExportPanel plotExportTab = new ComponentAnalysisPlotExportPanel(this, document,
generalTab.getParameters(), generalTab.getAerodynamicCalculator(), generalTab.getRocket());
tabbedPane.addTab(trans.get("ComponentAnalysisDialog.tab.PlotExport"), plotExportTab);
panel.add(tabbedPane, "span, pushy, grow, wrap");
@ -94,10 +95,10 @@ public class ComponentAnalysisDialog extends JDialog {
///////// Singleton implementation
public static void showDialog(RocketPanel rocketpanel) {
public static void showDialog(OpenRocketDocument document, RocketPanel rocketpanel) {
if (singletonDialog != null)
singletonDialog.dispose();
singletonDialog = new ComponentAnalysisDialog(rocketpanel);
singletonDialog = new ComponentAnalysisDialog(document, rocketpanel);
singletonDialog.setVisible(true);
}

View File

@ -6,6 +6,7 @@ import info.openrocket.core.componentanalysis.CADataType;
import info.openrocket.core.componentanalysis.CADomainDataType;
import info.openrocket.core.componentanalysis.CAParameterSweep;
import info.openrocket.core.componentanalysis.CAParameters;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.l10n.Translator;
import info.openrocket.core.rocketcomponent.Rocket;
import info.openrocket.core.rocketcomponent.RocketComponent;
@ -41,6 +42,7 @@ public class ComponentAnalysisPlotExportPanel extends JPanel implements PlotPane
private static final Logger log = LoggerFactory.getLogger(ComponentAnalysisPlotExportPanel.class);
private final Window parent;
private final OpenRocketDocument document;
private final JTabbedPane tabbedPane;
JComboBox<CADomainDataType> parameterSelector;
private JButton okButton;
@ -62,11 +64,13 @@ public class ComponentAnalysisPlotExportPanel extends JPanel implements PlotPane
private final Map<CADataType, List<RocketComponent>> componentCache;
private boolean isCacheValid;
public ComponentAnalysisPlotExportPanel(ComponentAnalysisDialog parent, CAParameters parameters,
AerodynamicCalculator aerodynamicCalculator, Rocket rocket) {
public ComponentAnalysisPlotExportPanel(ComponentAnalysisDialog parent, OpenRocketDocument document,
CAParameters parameters, AerodynamicCalculator aerodynamicCalculator,
Rocket rocket) {
super(new MigLayout("fill, height 700px!", "[]", "[grow]"));
this.parent = parent;
this.document = document;
this.parameters = parameters;
this.parameterSweep = new CAParameterSweep(parameters, aerodynamicCalculator, rocket);
this.componentCache = new HashMap<>();
@ -216,6 +220,10 @@ public class ComponentAnalysisPlotExportPanel extends JPanel implements PlotPane
});
}
public OpenRocketDocument getDocument() {
return document;
}
public CADomainDataType getSelectedParameter() {
return (CADomainDataType) parameterSelector.getSelectedItem();
}

View File

@ -0,0 +1,85 @@
package info.openrocket.swing.gui.dialogs.componentanalysis;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.l10n.Translator;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.core.startup.Application;
import info.openrocket.swing.gui.main.componenttree.SelectableComponentTree;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.tree.TreePath;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
public class ComponentSelectionDialog extends JDialog {
private static final Translator trans = Application.getTranslator();
private final SelectableComponentTree componentTree;
private List<RocketComponent> selectedComponents;
public ComponentSelectionDialog(Window owner, OpenRocketDocument document, List<RocketComponent> enabledComponents,
List<RocketComponent> initialSelection) {
super(owner, "Select Components", ModalityType.APPLICATION_MODAL);
// Component tree
componentTree = new SelectableComponentTree(document, enabledComponents, initialSelection);
JScrollPane scrollPane = new JScrollPane(componentTree);
// Confirm button
JButton confirmButton = new JButton(trans.get("ComponentSelectionDialog.btn.ConfirmSelection"));
confirmButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateSelectedComponents();
dispose();
}
});
// Cancel button
JButton cancelButton = new JButton(trans.get("button.cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
selectedComponents = null;
dispose();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(confirmButton);
buttonPanel.add(cancelButton);
setLayout(new BorderLayout());
add(scrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
setSize(400, 500);
setLocationRelativeTo(owner);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
}
private void updateSelectedComponents() {
TreePath[] selectedPaths = componentTree.getSelectionPaths();
selectedComponents = new ArrayList<>();
if (selectedPaths != null) {
for (TreePath path : selectedPaths) {
Object component = path.getLastPathComponent();
if (component instanceof RocketComponent) {
selectedComponents.add((RocketComponent) component);
}
}
}
}
public List<RocketComponent> showDialog() {
setVisible(true);
return selectedComponents;
}
}

View File

@ -663,7 +663,7 @@ public class BasicFrame extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
log.info(Markers.USER_MARKER, "Component analysis selected");
ComponentAnalysisDialog.showDialog(rocketpanel);
ComponentAnalysisDialog.showDialog(document, rocketpanel);
}
});
toolsMenu.add(item);

View File

@ -35,10 +35,6 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
private static final Translator trans = Application.getTranslator();
private static Color textSelectionBackgroundColor;
private static Color textSelectionForegroundColor;
private static Color componentTreeBackgroundColor;
private static Color componentTreeForegroundColor;
private static Color visibilityHiddenForegroundColor;
private static Icon massOverrideSubcomponentIcon;
private static Icon massOverrideIcon;

View File

@ -0,0 +1,42 @@
package info.openrocket.swing.gui.main.componenttree;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.rocketcomponent.RocketComponent;
import javax.swing.tree.TreePath;
import java.util.List;
import java.util.Set;
import java.util.HashSet;
public class SelectableComponentTree extends ComponentTree {
public SelectableComponentTree(OpenRocketDocument document, List<RocketComponent> enabledComponents,
List<RocketComponent> initialSelection) {
super(document);
Set<RocketComponent> enabledComponents1 = new HashSet<>(enabledComponents);
// Use a custom cell renderer that considers the enabled state
setCellRenderer(new SelectableComponentTreeRenderer(enabledComponents1));
// Use a custom selection model that allows toggling of selection
ToggleTreeSelectionModel selectionModel = new ToggleTreeSelectionModel();
setSelectionModel(selectionModel);
// Disable component selection for disabled components
for (RocketComponent component : document.getRocket()) {
if (!enabledComponents.contains(component)) {
TreePath path = ComponentTreeModel.makeTreePath(component);
selectionModel.addDisabledPath(path);
}
}
// Apply initial selection
selectionModel.setSelectionPath(null);
if (initialSelection != null && !initialSelection.isEmpty()) {
for (RocketComponent component : initialSelection) {
TreePath path = ComponentTreeModel.makeTreePath(component);
selectionModel.addSelectionPath(path);
}
}
}
}

View File

@ -0,0 +1,78 @@
package info.openrocket.swing.gui.main.componenttree;
import info.openrocket.core.rocketcomponent.RocketComponent;
import info.openrocket.swing.gui.theme.UITheme;
import info.openrocket.swing.gui.util.GUIUtil;
import info.openrocket.swing.gui.util.Icons;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.util.Set;
public class SelectableComponentTreeRenderer extends ComponentTreeRenderer {
private final Set<RocketComponent> enabledComponents;
private static Color disabledTextColor;
private static Font regularFont;
private static Font italicFont;
static {
initColors();
initFonts();
}
public SelectableComponentTreeRenderer(Set<RocketComponent> enabledComponents) {
this.enabledComponents = enabledComponents;
}
private static void initColors() {
updateColors();
UITheme.Theme.addUIThemeChangeListener(SelectableComponentTreeRenderer::updateColors);
}
private static void initFonts() {
regularFont = UIManager.getFont("Tree.font");
italicFont = regularFont.deriveFont(Font.ITALIC);
}
private static void updateColors() {
disabledTextColor = GUIUtil.getUITheme().getDisabledTextColor();
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
Component rendererComponent = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
if (value instanceof RocketComponent component) {
boolean isEnabled = enabledComponents.contains(component);
rendererComponent.setEnabled(isEnabled);
if (rendererComponent instanceof JPanel panel) {
for (Component c : panel.getComponents()) {
if (c instanceof JLabel label) {
if (!isEnabled) {
label.setForeground(disabledTextColor);
label.setFont(italicFont);
Icon icon = label.getIcon();
if (icon != null) {
label.setIcon(Icons.createDisabledIcon(icon));
}
} else {
label.setFont(regularFont);
}
}
}
}
}
return rendererComponent;
}
}

View File

@ -0,0 +1,53 @@
package info.openrocket.swing.gui.main.componenttree;
import javax.swing.tree.DefaultTreeSelectionModel;
import javax.swing.tree.TreePath;
import java.util.HashSet;
import java.util.Set;
public class ToggleTreeSelectionModel extends DefaultTreeSelectionModel {
private final Set<TreePath> disabledPaths;
public ToggleTreeSelectionModel() {
setSelectionMode(DISCONTIGUOUS_TREE_SELECTION);
disabledPaths = new HashSet<>();
}
@Override
public void setSelectionPath(TreePath path) {
if (isPathEnabled(path)) {
if (isPathSelected(path)) {
removeSelectionPath(path);
} else {
addSelectionPath(path);
}
}
}
@Override
public void addSelectionPath(TreePath path) {
if (isPathEnabled(path)) {
super.addSelectionPath(path);
}
}
@Override
public void removeSelectionPath(TreePath path) {
if (isPathEnabled(path)) {
super.removeSelectionPath(path);
}
}
public void addDisabledPath(TreePath path) {
disabledPaths.add(path);
removeSelectionPath(path);
}
public void removeDisabledPath(TreePath path) {
disabledPaths.remove(path);
}
public boolean isPathEnabled(TreePath path) {
return !disabledPaths.contains(path);
}
}

View File

@ -52,19 +52,19 @@ public class PlotTypeSelector<T extends Groupable<G> & UnitValue, G extends Grou
}
};
typeSelector.setSelectedItem(type);
this.add(typeSelector, "gapright para");
this.add(typeSelector, "gapright para, top");
this.add(new JLabel("Unit:"));
this.add(new JLabel("Unit:"), "top");
unitSelector = new UnitSelector(type.getUnitGroup());
if (unit != null) {
unitSelector.setSelectedUnit(unit);
}
this.add(unitSelector, "width 40lp, gapright para");
this.add(unitSelector, "width 40lp, gapright para, top");
this.add(new JLabel("Axis:"));
this.add(new JLabel("Axis:"), "top");
axisSelector = new JComboBox<>(POSITIONS);
axisSelector.setSelectedIndex(position + 1);
this.add(axisSelector);
this.add(axisSelector, "top");
removeButton = new JButton(Icons.EDIT_DELETE);
removeButton.setToolTipText("Remove this plot");
@ -79,7 +79,7 @@ public class PlotTypeSelector<T extends Groupable<G> & UnitValue, G extends Grou
}
protected void addRemoveButton() {
this.add(removeButton, "gapright 0");
this.add(removeButton, "gapright 0, top");
}
public int getIndex() {

View File

@ -44,7 +44,7 @@ public class SimulationExportPanel extends CSVExportPanel<FlightDataType> {
private SimulationExportPanel(Simulation simulation, FlightDataBranch branch, FlightDataType[] types,
boolean[] selected, CsvOptionPanel csvOptions, Component... extraComponents) {
super(types, selected, csvOptions, extraComponents);
super(types, selected, csvOptions, false, extraComponents);
this.simulation = simulation;
this.branch = branch;
}
@ -165,4 +165,9 @@ public class SimulationExportPanel extends CSVExportPanel<FlightDataType> {
return true;
}
@Override
protected String getDisplayName(FlightDataType type) {
return type.getName();
}
}

View File

@ -1041,7 +1041,7 @@ public class UITheme {
@Override
public Color getDisabledTextColor() {
return new Color(128, 128, 128);
return new Color(128, 128, 128, 223);
}

View File

@ -7,11 +7,13 @@ import info.openrocket.core.startup.Application;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.GrayFilter;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
@ -183,4 +185,13 @@ public class Icons {
}
};
}
public static Icon createDisabledIcon(Icon icon) {
Image image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
icon.paintIcon(null, g, 0, 0);
g.dispose();
return new ImageIcon(GrayFilter.createDisabledImage(((ImageIcon) icon).getImage()));
}
}

View File

@ -3,334 +3,240 @@ package info.openrocket.swing.gui.widgets;
import info.openrocket.core.l10n.Translator;
import info.openrocket.core.startup.Application;
import info.openrocket.core.unit.Unit;
import info.openrocket.core.unit.UnitGroup;
import info.openrocket.core.util.UnitValue;
import info.openrocket.swing.gui.components.CsvOptionPanel;
import info.openrocket.swing.gui.components.UnitCellEditor;
import info.openrocket.swing.gui.components.UnitSelector;
import info.openrocket.swing.gui.theme.UITheme;
import info.openrocket.swing.gui.util.GUIUtil;
import net.miginfocom.swing.MigLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.UIManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.List;
public class CSVExportPanel<T extends UnitValue> extends JPanel {
private static final Translator trans = Application.getTranslator();
private static final long serialVersionUID = 1L;
protected static final Translator trans = Application.getTranslator();
protected static final String SPACE = "SPACE";
protected static final String TAB = "TAB";
private static Color ALTERNATE_ROW_COLOR;
protected final JTable table;
protected final SelectionTableModel tableModel;
private final JLabel selectedCountLabel;
protected final boolean[] selected;
protected final T[] types;
protected final Unit[] units;
protected final List<DataTypeRow> dataTypeRows = new ArrayList<>();
protected final CsvOptionPanel csvOptions;
protected final JLabel selectedCountLabel;
public CSVExportPanel(T[] types, boolean[] selected, CsvOptionPanel csvOptions, boolean separateRowForTable, Component... extraComponents) {
super(new MigLayout("fill, flowy"));
protected final T[] types;
protected boolean[] selected;
protected Unit[] units;
static {
initColors();
}
public CSVExportPanel(T[] types, boolean[] selected, CsvOptionPanel csvOptions, boolean separateRowForOptions,
Component... extraComponents) {
super(new MigLayout("fill, wrap 2", "[grow,fill][]", "[grow,fill][]"));
this.types = types;
this.selected = selected;
this.csvOptions = csvOptions;
this.units = new Unit[types.length];
for (int i = 0; i < types.length; i++) {
units[i] = types[i].getUnitGroup().getDefaultUnit();
}
//// Create the panel
JPanel panel;
JButton button;
JPanel exportPanel = new JPanel(new MigLayout("ins 0, fill"));
// Set up the variable selection table
tableModel = createTableModel();
table = new JTable(tableModel);
initializeTable(types);
boolean addExtras = createExtraComponent(types[0], 0) != null;
JPanel contentPanel = new JPanel(new GridBagLayout());
contentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(0, 0, 0, 0); // No padding
c.fill = GridBagConstraints.BOTH;
// Add table
panel = new JPanel(new MigLayout("fill"));
panel.setBorder(BorderFactory.createTitledBorder(trans.get("SimExpPan.border.Vartoexport")));
// Header
c.gridy = 0;
c.weightx = 0;
addHeaderRowLabel(contentPanel, "CSVExportPanel.lbl.Export", c, 0);
c.weightx = 1;
addHeaderRowLabel(contentPanel, "CSVExportPanel.lbl.Variable", c, 1);
c.weightx = 0;
addHeaderRowLabel(contentPanel, "CSVExportPanel.lbl.Unit", c, 2);
if (addExtras) {
c.weightx = 1;
addHeaderRowLabel(contentPanel, getExtraColumnLabelKey(), c, 3);
}
panel.add(new JScrollPane(table), "wmin 300lp, width 300lp, pushy, grow 100, wrap");
// Data rows
for (int i = 0; i < types.length; i++) {
DataTypeRow row = new DataTypeRow(types[i], selected[i], units[i], i);
dataTypeRows.add(row);
Color bgColor = i % 2 == 0 ? UIManager.getColor("Table.background") : ALTERNATE_ROW_COLOR;
c.gridy = i + 1;
addDataRowWidget(contentPanel, row.exportCheckBox, c, bgColor, 0);
addDataRowWidget(contentPanel, row.nameLabel, c, bgColor, 1);
addDataRowWidget(contentPanel, row.unitSelector, c, bgColor, 2);
if (addExtras) {
addDataRowWidget(contentPanel, createExtraComponent(types[i], i), c, bgColor, 3);
}
}
JScrollPane scrollPane = new JScrollPane(contentPanel);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setPreferredSize(new Dimension(300, 400));
exportPanel.add(scrollPane, "grow, wrap");
// Select all/none buttons
button = new JButton(trans.get("SimExpPan.but.Selectall"));
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tableModel.selectAll();
}
});
panel.add(button, "split 2, growx 1, sizegroup selectbutton");
JPanel buttonPanel = new JPanel(new MigLayout("insets 0"));
JButton selectAllButton = new JButton(trans.get("CSVExportPanel.but.Selectall"));
selectAllButton.addActionListener(e -> selectAll());
buttonPanel.add(selectAllButton, "split 2, growx");
button = new JButton(trans.get("SimExpPan.but.Selectnone"));
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
tableModel.selectNone();
}
});
panel.add(button, "growx 1, sizegroup selectbutton, wrap");
JButton selectNoneButton = new JButton(trans.get("CSVExportPanel.but.Selectnone"));
selectNoneButton.addActionListener(e -> selectNone());
buttonPanel.add(selectNoneButton, "growx");
exportPanel.add(buttonPanel, "growx, wrap");
// Exporting xx variables out of yy
// Selected count label
selectedCountLabel = new JLabel();
updateSelectedCount();
panel.add(selectedCountLabel);
exportPanel.add(selectedCountLabel, "growx");
add(exportPanel, "grow, gapright para" + (separateRowForOptions ? ", spanx, wrap" : ""));
if (separateRowForTable) {
this.add(panel, "spanx, grow 100, wrap");
} else {
this.add(panel, "grow 100, wrap");
}
// Add CSV options
if (separateRowForTable) {
this.add(csvOptions, "grow 1");
} else {
this.add(csvOptions, "spany, split, growx 1");
}
//// Add extra widgets
if (extraComponents != null) {
for (Component c : extraComponents) {
if (separateRowForTable) {
this.add(c, "grow 1");
} else {
this.add(c, "spany, split, growx 1");
}
// CSV options and extra components
if (separateRowForOptions) {
add(csvOptions, "growx");
for (Component comp : extraComponents) {
add(comp, "growx, top");
}
}
// Space-filling panel
if (!separateRowForTable) {
panel = new JPanel();
this.add(panel, "width 1, height 1, grow 1");
}
}
public CSVExportPanel(T[] types, boolean[] selected, CsvOptionPanel csvOptions, Component... extraComponents) {
this(types, selected, csvOptions, false, extraComponents);
}
protected SelectionTableModel createTableModel() {
return new SelectionTableModel();
}
protected void initializeTable(T[] types) {
table.setDefaultRenderer(Object.class,
new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Object.class)));
table.setDefaultRenderer(Boolean.class,
new SelectionBackgroundCellRenderer(table.getDefaultRenderer(Boolean.class)));
table.setRowSelectionAllowed(false);
table.setColumnSelectionAllowed(false);
table.setDefaultEditor(Unit.class, new UnitCellEditor() {
private static final long serialVersionUID = 1088570433902420935L;
@Override
protected UnitGroup getUnitGroup(Unit value, int row, int column) {
return types[row].getUnitGroup();
} else {
JPanel optionsPanel = new JPanel(new MigLayout("insets 0"));
optionsPanel.add(csvOptions, "growx");
for (Component comp : extraComponents) {
optionsPanel.add(comp, "growx");
}
});
// Set column widths
TableColumnModel columnModel = table.getColumnModel();
TableColumn col = columnModel.getColumn(0);
int w = table.getRowHeight();
col.setMinWidth(w);
col.setPreferredWidth(w);
col.setMaxWidth(w);
col = columnModel.getColumn(1);
col.setPreferredWidth(200);
col = columnModel.getColumn(2);
col.setPreferredWidth(100);
table.addMouseListener(new GUIUtil.BooleanTableClickListener(table));
add(optionsPanel, "growx, top");
}
}
public boolean doExport() {
throw new RuntimeException("Not implemented");
private static void initColors() {
updateColors();
UITheme.Theme.addUIThemeChangeListener(CSVExportPanel::updateColors);
}
private void updateSelectedCount() {
private static void updateColors() {
ALTERNATE_ROW_COLOR = GUIUtil.getUITheme().getRowBackgroundLighterColor();
}
private void addHeaderRowLabel(JPanel contentPanel, String lblKey, GridBagConstraints c, int x) {
c.gridx = x;
JPanel panel = new JPanel(new MigLayout("fill, ins 4 5 4 5"));
panel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, UIManager.getColor("Table.gridColor")));
panel.add(new JLabel("<html><b>" + trans.get(lblKey) + "</b></html>"), "growx");
contentPanel.add(panel, c);
}
private void addDataRowWidget(JPanel contentPanel, Component widget, GridBagConstraints c, Color bgColor, int x) {
c.gridx = x;
JPanel panel = new JPanel(new MigLayout("fill, ins 4 5 4 5"));
panel.setBackground(bgColor);
if (widget instanceof JPanel) {
widget.setBackground(bgColor);
}
panel.add(widget, "growx");
contentPanel.add(panel, c);
}
protected String getExtraColumnLabelKey() {
return "CSVExportPanel.lbl.Extra";
}
protected Component createExtraComponent(T type, int index) {
return null;
}
protected class DataTypeRow {
final JCheckBox exportCheckBox;
final JLabel nameLabel;
final UnitSelector unitSelector;
final int index;
DataTypeRow(T type, boolean isSelected, Unit unit, int index) {
this.index = index;
exportCheckBox = new JCheckBox();
exportCheckBox.setSelected(isSelected);
exportCheckBox.addActionListener(e -> {
selected[index] = exportCheckBox.isSelected();
updateSelectedCount();
});
nameLabel = new JLabel(getDisplayName(type));
unitSelector = new UnitSelector(type.getUnitGroup());
unitSelector.setSelectedUnit(unit);
unitSelector.addItemListener(e -> units[index] = unitSelector.getSelectedUnit());
}
}
protected String getDisplayName(T type) {
return type.toString();
}
protected void selectAll() {
for (DataTypeRow row : dataTypeRows) {
row.exportCheckBox.setSelected(true);
selected[row.index] = true;
}
updateSelectedCount();
}
protected void selectNone() {
for (DataTypeRow row : dataTypeRows) {
row.exportCheckBox.setSelected(false);
selected[row.index] = false;
}
updateSelectedCount();
}
protected void updateSelectedCount() {
int total = selected.length;
int n = 0;
String str;
for (boolean b : selected) {
if (b)
n++;
if (b) n++;
}
String str;
if (n == 1) {
//// Exporting 1 variable out of
str = trans.get("SimExpPan.ExportingVar.desc1") + " " + total + ".";
str = trans.get("CSVExportPanel.ExportingVar.desc1") + " " + total + ".";
} else {
//// Exporting
//// variables out of
str = trans.get("SimExpPan.ExportingVar.desc2") + " " + n + " " +
trans.get("SimExpPan.ExportingVar.desc3") + " " + total + ".";
str = trans.get("CSVExportPanel.ExportingVar.desc2") + " " + n + " " +
trans.get("CSVExportPanel.ExportingVar.desc3") + " " + total + ".";
}
selectedCountLabel.setText(str);
}
/**
* The table model for the variable selection.
*/
protected class SelectionTableModel extends AbstractTableModel {
private static final long serialVersionUID = 493067422917621072L;
protected static final int SELECTED = 0;
protected static final int NAME = 1;
protected static final int UNIT = 2;
@Override
public int getColumnCount() {
return 3;
}
@Override
public int getRowCount() {
return types.length;
}
@Override
public String getColumnName(int column) {
return switch (column) {
case SELECTED -> "";
case NAME ->
//// Variable
trans.get("SimExpPan.Col.Variable");
case UNIT ->
//// Unit
trans.get("SimExpPan.Col.Unit");
default -> throw new IndexOutOfBoundsException("column=" + column);
};
}
@Override
public Class<?> getColumnClass(int column) {
return switch (column) {
case SELECTED -> Boolean.class;
case NAME -> new TypeToken<T>(){}.getType().getClass();
case UNIT -> Unit.class;
default -> throw new IndexOutOfBoundsException("column=" + column);
};
}
@Override
public Object getValueAt(int row, int column) {
return switch (column) {
case SELECTED -> selected[row];
case NAME -> types[row];
case UNIT -> units[row];
default -> throw new IndexOutOfBoundsException("column=" + column);
};
}
@Override
public void setValueAt(Object value, int row, int column) {
switch (column) {
case SELECTED:
selected[row] = (Boolean) value;
this.fireTableRowsUpdated(row, row);
updateSelectedCount();
break;
case NAME:
break;
case UNIT:
units[row] = (Unit) value;
break;
default:
throw new IndexOutOfBoundsException("column=" + column);
}
}
@Override
public boolean isCellEditable(int row, int column) {
return switch (column) {
case SELECTED -> true;
case NAME -> false;
case UNIT -> types[row].getUnitGroup().getUnitCount() > 1;
default -> throw new IndexOutOfBoundsException("column=" + column);
};
}
public void selectAll() {
Arrays.fill(selected, true);
updateSelectedCount();
this.fireTableDataChanged();
}
public void selectNone() {
Arrays.fill(selected, false);
updateSelectedCount();
this.fireTableDataChanged();
}
public boolean doExport() {
throw new UnsupportedOperationException("Export not implemented in base class");
}
/**
* A table cell renderer that uses another renderer and sets the background and
* foreground of the returned component based on the selection of the variable.
*/
private class SelectionBackgroundCellRenderer implements TableCellRenderer {
private final TableCellRenderer renderer;
public SelectionBackgroundCellRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
}
@Override
public Component getTableCellRendererComponent(JTable myTable, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component component = renderer.getTableCellRendererComponent(myTable,
value, isSelected, hasFocus, row, column);
if (selected[row]) {
component.setBackground(myTable.getSelectionBackground());
component.setForeground(myTable.getSelectionForeground());
} else {
component.setBackground(myTable.getBackground());
component.setForeground(myTable.getForeground());
}
return component;
}
}
public abstract static class TypeToken<T> {
private final Type type;
protected TypeToken(){
Type superClass = getClass().getGenericSuperclass();
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() {
return type;
}
}
}
}