diff --git a/swing/src/main/java/info/openrocket/swing/gui/configdialog/MaterialPanel.java b/swing/src/main/java/info/openrocket/swing/gui/configdialog/MaterialPanel.java index 089e0fdba..c03015a16 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/configdialog/MaterialPanel.java +++ b/swing/src/main/java/info/openrocket/swing/gui/configdialog/MaterialPanel.java @@ -28,11 +28,7 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; /** * Panel for configuring a component's material and finish properties. @@ -63,11 +59,6 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating @Override public void run() { mm.addCustomMaterial(); - if (MaterialPanel.this.materialCombo != null) { - MaterialComboBox.updateComboBoxItems(MaterialPanel.this.materialCombo, MaterialGroup.ALL_GROUPS, - mm.getAllMaterials()); - MaterialPanel.this.materialCombo.setSelectedItem(mm.getSelectedItem()); - } } }); }); @@ -89,8 +80,7 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating }); // Material selection combo box - this.materialCombo = MaterialComboBox.createComboBox(mm, MaterialGroup.ALL_GROUPS, mm.getAllMaterials(), - customMaterialButton, editMaterialsButton); + this.materialCombo = MaterialComboBox.createComboBox(mm, customMaterialButton, editMaterialsButton); this.materialCombo.setSelectedItem(mm.getSelectedItem()); this.materialCombo.setToolTipText(trans.get("MaterialPanel.combo.ttip.ComponentMaterialAffects")); this.add(this.materialCombo, "spanx 4, growx, wrap paragraph"); @@ -171,10 +161,8 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating private static final Translator trans = Application.getTranslator(); public static SearchableAndCategorizableComboBox createComboBox( - MaterialModel mm, MaterialGroup[] allGroups, Material[] materials, Component... extraCategoryWidgets) { - final Map> materialGroupMap = - createMaterialGroupMap(allGroups, materials); - return new SearchableAndCategorizableComboBox<>(mm, materialGroupMap, + MaterialModel mm, Component... extraCategoryWidgets) { + return new SearchableAndCategorizableComboBox<>(mm, trans.get("MaterialPanel.MaterialComboBox.placeholder"), extraCategoryWidgets) { @Override public String getDisplayString(Material item) { @@ -186,47 +174,5 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating } }; } - - public static void updateComboBoxItems(SearchableAndCategorizableComboBox comboBox, - MaterialGroup[] allGroups, Material[] materials) { - final Map> materialGroupMap = createMaterialGroupMap(allGroups, materials); - comboBox.updateItems(materialGroupMap); - comboBox.invalidate(); - comboBox.repaint(); - } - - /** - * Create a map of material group and corresponding material. - * @param groups the groups - * @param materials the materials - * @return the map linking the materials to their groups - */ - private static Map> createMaterialGroupMap( - MaterialGroup[] groups, Material[] materials) { - // Sort the groups based on priority (lower number = higher priority) - MaterialGroup[] sortedGroups = groups.clone(); - Arrays.sort(sortedGroups, Comparator.comparingInt(MaterialGroup::getPriority)); - - Map> map = new LinkedHashMap<>(); - MaterialGroup materialGroup; - for (MaterialGroup group : sortedGroups) { - List itemsForGroup = new ArrayList<>(); - for (Material material : materials) { - materialGroup = material.getGroup(); - if (materialGroup.equals(group)) { - itemsForGroup.add(material); - } - } - // Sort the types within each group based on priority - itemsForGroup.sort(Comparator.comparingInt(Material::getGroupPriority)); - - map.put(group, itemsForGroup); - } - - // Remove empty groups - map.entrySet().removeIf(entry -> entry.getValue().isEmpty()); - - return map; - } } } diff --git a/swing/src/main/java/info/openrocket/swing/gui/simulation/FlightDataComboBox.java b/swing/src/main/java/info/openrocket/swing/gui/simulation/FlightDataComboBox.java index cd74bb6f0..49ab8eef1 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/simulation/FlightDataComboBox.java +++ b/swing/src/main/java/info/openrocket/swing/gui/simulation/FlightDataComboBox.java @@ -17,9 +17,8 @@ import java.util.Map; public class FlightDataComboBox extends JComboBox { private static final Translator trans = Application.getTranslator(); - public static SearchableAndCategorizableComboBox createComboBox(FlightDataTypeGroup[] allGroups, FlightDataType[] types) { - final Map> typeGroupMap = createFlightDataGroupMap(allGroups, types); - return new SearchableAndCategorizableComboBox<>(typeGroupMap, trans.get("FlightDataComboBox.placeholder")); + public static SearchableAndCategorizableComboBox createComboBox(List types) { + return new SearchableAndCategorizableComboBox<>(types, trans.get("FlightDataComboBox.placeholder")); } /** diff --git a/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java b/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java index 9b3b60004..5a224c6b0 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java +++ b/swing/src/main/java/info/openrocket/swing/gui/simulation/SimulationPlotPanel.java @@ -173,7 +173,7 @@ public class SimulationPlotPanel extends JPanel { //// X axis type: this.add(new JLabel(trans.get("simplotpanel.lbl.Xaxistype")), "spanx, split"); - domainTypeSelector = FlightDataComboBox.createComboBox(FlightDataTypeGroup.ALL_GROUPS, types); + domainTypeSelector = FlightDataComboBox.createComboBox(Arrays.asList(types)); domainTypeSelector.setSelectedItem(configuration.getDomainAxisType()); domainTypeSelector.addItemListener(new ItemListener() { @Override @@ -497,7 +497,7 @@ public class SimulationPlotPanel extends JPanel { this.index = plotIndex; - typeSelector = FlightDataComboBox.createComboBox(FlightDataTypeGroup.ALL_GROUPS, types); + typeSelector = FlightDataComboBox.createComboBox(Arrays.asList(types)); typeSelector.setSelectedItem(type); typeSelector.addItemListener(new ItemListener() { @Override diff --git a/swing/src/main/java/info/openrocket/swing/gui/widgets/SearchableAndCategorizableComboBox.java b/swing/src/main/java/info/openrocket/swing/gui/widgets/SearchableAndCategorizableComboBox.java index 656e7f0a6..6894eaa96 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/widgets/SearchableAndCategorizableComboBox.java +++ b/swing/src/main/java/info/openrocket/swing/gui/widgets/SearchableAndCategorizableComboBox.java @@ -28,6 +28,8 @@ import java.awt.Component; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; @@ -45,8 +47,10 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.SortedSet; +import java.util.TreeMap; import java.util.TreeSet; import java.util.Vector; @@ -63,12 +67,12 @@ public class SearchableAndCategorizableComboBox filteredList; private Map> itemGroupMap; @@ -84,19 +88,34 @@ public class SearchableAndCategorizableComboBox model, Map> itemGroupMap, String placeHolderText, + public SearchableAndCategorizableComboBox(ComboBoxModel model, String placeHolderText, Component... extraCategoryWidgets) { super(model != null ? model : new DefaultComboBoxModel<>()); + List items = new ArrayList<>(); + for (int i = 0; i < Objects.requireNonNull(model).getSize(); i++) { + items.add(model.getElementAt(i)); + } + + init(model, constructItemGroupMapFromList(items), placeHolderText, extraCategoryWidgets); + } + + public SearchableAndCategorizableComboBox(List allItems, String placeHolderText, Component... extraCategoryWidgets) { + super(); + + init(null, constructItemGroupMapFromList(allItems), placeHolderText, extraCategoryWidgets); + } + + private void init(ComboBoxModel model, Map> itemGroupMap, String placeHolderText, Component... extraCategoryWidgets) { setEditable(false); initColors(); this.extraCategoryWidgets = extraCategoryWidgets; this.placeHolderText = placeHolderText; + this.itemGroupMap = itemGroupMap; updateItems(itemGroupMap); setupMainRenderer(); @@ -105,10 +124,6 @@ public class SearchableAndCategorizableComboBox> itemGroupMap, String placeHolderText, Component... extraCategoryWidgets) { - this(null, itemGroupMap, placeHolderText, extraCategoryWidgets); - } - private static void initColors() { updateColors(); UITheme.Theme.addUIThemeChangeListener(SearchableAndCategorizableComboBox::updateColors); @@ -118,6 +133,21 @@ public class SearchableAndCategorizableComboBox> constructItemGroupMapFromList(List items) { + Map> itemGroupMap = new TreeMap<>(new Comparator() { + @Override + public int compare(G g1, G g2) { + return Integer.compare(g1.getPriority(), g2.getPriority()); + } + }); + + for (T item : items) { + G group = item.getGroup(); + itemGroupMap.computeIfAbsent(group, k -> new ArrayList<>()).add(item); + } + return itemGroupMap; + } + public void setupMainRenderer() { setRenderer(new DefaultListCellRenderer() { @Override @@ -173,20 +203,6 @@ public class SearchableAndCategorizableComboBox model = getModel(); - Map> newGroupMap = new HashMap<>(); - - for (int i = 0; i < model.getSize(); i++) { - T item = model.getElementAt(i); - G group = item.getGroup(); - newGroupMap.computeIfAbsent(group, k -> new ArrayList<>()).add(item); - } - - Map> newItemGroupMap = new HashMap<>(newGroupMap); - updateItems(newItemGroupMap); - } - private List extractItemsFromMap(Map> itemGroupMap) { Set uniqueItems = new HashSet<>(); // Use a Set to ensure uniqueness for (G group : itemGroupMap.keySet()) { @@ -425,6 +441,12 @@ public class SearchableAndCategorizableComboBox