Use searchable and categorizable combobox for material panel

This commit is contained in:
SiboVG 2024-07-21 11:26:08 +02:00
parent 3f8a118298
commit 4411cb1b35
7 changed files with 481 additions and 208 deletions

View File

@ -1,5 +1,6 @@
package info.openrocket.core.database;
import info.openrocket.core.material.MaterialGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -40,89 +41,89 @@ public class Databases {
static {
// Add default materials
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Acrylic", 1190));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Aluminum", 2700));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Balsa", 170));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Basswood", 500));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Birch", 670));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Brass", 8600));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Cardboard", 680));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Carbon fiber", 1780));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Cork", 240));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Delrin", 1420));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Depron (XPS)", 40));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Fiberglass", 1850));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Kraft phenolic", 950));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Maple", 755));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Nylon", 1150));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Paper (office)", 820));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Pine", 530));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Plywood (birch)", 630));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Polycarbonate (Lexan)", 1200));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Polystyrene", 1050));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PVC", 1390));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Spruce", 450));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Steel", 7850));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Styrofoam (generic EPS)", 20));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Styrofoam \"Blue foam\" (XPS)", 32));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Titanium", 4500));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Quantum tubing", 1050));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Blue tube", 1300));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PLA - 100% infill", 1250));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PETG - 100% infill", 1250));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "ABS - 100% infill", 1050));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Acrylic", 1190, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Aluminum", 2700, MaterialGroup.METALS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Balsa", 170, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Basswood", 500, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Birch", 670, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Brass", 8600, MaterialGroup.METALS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Cardboard", 680, MaterialGroup.PAPER));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Carbon fiber", 1780, MaterialGroup.COMPOSITES));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Cork", 240, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Delrin", 1420, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Depron (XPS)", 40, MaterialGroup.FOAMS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Fiberglass", 1850, MaterialGroup.COMPOSITES));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Kraft phenolic", 950, MaterialGroup.COMPOSITES));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Maple", 755, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Nylon", 1150, MaterialGroup.FIBERS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Paper (office)", 820, MaterialGroup.PAPER));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Pine", 530, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Plywood (birch)", 630, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Polycarbonate (Lexan)", 1200, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Polystyrene", 1050, MaterialGroup.FOAMS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PVC", 1390, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Spruce", 450, MaterialGroup.WOODS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Steel", 7850, MaterialGroup.METALS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Styrofoam (generic EPS)", 20, MaterialGroup.FOAMS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Styrofoam \"Blue foam\" (XPS)", 32, MaterialGroup.FOAMS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Titanium", 4500, MaterialGroup.METALS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Quantum tubing", 1050, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Blue tube", 1300, MaterialGroup.COMPOSITES));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PLA - 100% infill", 1250, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PETG - 100% infill", 1250, MaterialGroup.PLASTICS));
BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "ABS - 100% infill", 1050, MaterialGroup.PLASTICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Ripstop nylon", 0.067));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Mylar", 0.021));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Polyethylene (thin)", 0.015));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Polyethylene (heavy)", 0.040));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Silk", 0.060));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Paper (office)", 0.080));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Cellophane", 0.018));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Cr\u00eape paper", 0.025));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Ripstop nylon", 0.067, MaterialGroup.FABRICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Mylar", 0.021, MaterialGroup.PLASTICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Polyethylene (thin)", 0.015, MaterialGroup.PLASTICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Polyethylene (heavy)", 0.040, MaterialGroup.PLASTICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Silk", 0.060, MaterialGroup.FABRICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Paper (office)", 0.080, MaterialGroup.PAPER));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Cellophane", 0.018, MaterialGroup.PLASTICS));
SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Cr\u00eape paper", 0.025, MaterialGroup.PAPER));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Thread (heavy-duty)", 0.0003));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)", 0.0018));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 6 mm, 1/4 in)", 0.0043));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 12 mm, 1/2 in)", 0.008));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 19 mm, 3/4 in)", 0.0012));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 25 mm, 1 in)", 0.0016));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Braided nylon (2 mm, 1/16 in)", 0.001));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Braided nylon (3 mm, 1/8 in)", 0.0035));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (11 mm, 7/16 in)", 0.013));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (14 mm, 9/16 in)", 0.016));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (25 mm, 1 in)", 0.029));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 138 (0.4 mm, 1/64 in)", 0.00014808));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 207 (0.5 mm, 1/64 in)", 0.00023622));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 346 (0.7 mm, 1/32 in)", 0.00047243));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 415 (0.8 mm, 1/32 in)", 0.00055117));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 800 (1.1 mm, 3/64 in)", 0.00099211));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (3.2 mm, 1/8 in)", 0.00967306));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (4.8 mm, 3/16 in)", 0.01785797));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (6.4 mm, 1/4 in)", 0.02976328));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (7.9 mm, 5/16 in)", 0.04464491));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (10 mm, 3/8 in)", 0.05952655));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (11 mm, 7/16 in)", 0.07440819));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (13 mm, 1/2 in)", 0.11607678));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (14 mm, 9/16 in)", 0.20834293));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (16 mm, 5/8 in)", 0.28721562));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (19 mm, 3/4 in)", 0.3497185));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (25 mm, 1 in)", 0.45686629));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing md. (10 mm, 3/8 in)", 0.00951444));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing md. (13 mm, 1/2 in)", 0.01334208));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing md. (16 mm, 5/8 in)", 0.01618548));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing lg. (14 mm, 9/16 in)", 0.02723097));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing lg. (25 mm, 1 in)", 0.03969816));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Paraline small IIIA (6.4 mm, 1.4 in)", 0.00371829));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic rubber band (flat 3.2 mm, 1/8 in)", 0.00297638));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic rubber band (flat 6.4 mm, 1/4 in)", 0.00613107));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 3.2 mm, 1/8 in)", 0.00106));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 4 mm, 5/32 in)", 0.002));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 6.4 mm, 1/4 in)", 0.00254));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (round 2 mm, 1/16 in)", 0.0035));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (round 2.5 mm, 3/32 in)", 0.0038));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 10 mm, 3/8 in)", 0.00381));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 13 mm, 1/2 in)", 0.00551172));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Thread (heavy-duty)", 0.0003, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)", 0.0018, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 6 mm, 1/4 in)", 0.0043, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 12 mm, 1/2 in)", 0.008, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 19 mm, 3/4 in)", 0.0012, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 25 mm, 1 in)", 0.0016, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Braided nylon (2 mm, 1/16 in)", 0.001, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Braided nylon (3 mm, 1/8 in)", 0.0035, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (11 mm, 7/16 in)", 0.013, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (14 mm, 9/16 in)", 0.016, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (25 mm, 1 in)", 0.029, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 138 (0.4 mm, 1/64 in)", 0.00014808, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 207 (0.5 mm, 1/64 in)", 0.00023622, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 346 (0.7 mm, 1/32 in)", 0.00047243, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 415 (0.8 mm, 1/32 in)", 0.00055117, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar thread 800 (1.1 mm, 3/64 in)", 0.00099211, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (3.2 mm, 1/8 in)", 0.00967306, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (4.8 mm, 3/16 in)", 0.01785797, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (6.4 mm, 1/4 in)", 0.02976328, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (7.9 mm, 5/16 in)", 0.04464491, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (10 mm, 3/8 in)", 0.05952655, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (11 mm, 7/16 in)", 0.07440819, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (13 mm, 1/2 in)", 0.11607678, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (14 mm, 9/16 in)", 0.20834293, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (16 mm, 5/8 in)", 0.28721562, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (19 mm, 3/4 in)", 0.3497185, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Kevlar 12-strand (25 mm, 1 in)", 0.45686629, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing md. (10 mm, 3/8 in)", 0.00951444, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing md. (13 mm, 1/2 in)", 0.01334208, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing md. (16 mm, 5/8 in)", 0.01618548, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing lg. (14 mm, 9/16 in)", 0.02723097, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Nylon flat webbing lg. (25 mm, 1 in)", 0.03969816, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Paraline small IIIA (6.4 mm, 1.4 in)", 0.00371829, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic rubber band (flat 3.2 mm, 1/8 in)", 0.00297638, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic rubber band (flat 6.4 mm, 1/4 in)", 0.00613107, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 3.2 mm, 1/8 in)", 0.00106, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 4 mm, 5/32 in)", 0.002, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 6.4 mm, 1/4 in)", 0.00254, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (round 2 mm, 1/16 in)", 0.0035, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (round 2.5 mm, 3/32 in)", 0.0038, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 10 mm, 3/8 in)", 0.00381, MaterialGroup.THREADS_LINES));
LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic braided cord (flat 13 mm, 1/2 in)", 0.00551172, MaterialGroup.THREADS_LINES));
// Add user-defined materials
@ -159,9 +160,13 @@ public class Databases {
* @param density density
* @return a new object with the material data
*/
private static Material newMaterial(Type type, String baseName, double density) {
private static Material newMaterial(Type type, String baseName, double density, MaterialGroup group) {
String name = trans.get("material", baseName);
return Material.newMaterial(type, name, density, false);
return Material.newMaterial(type, name, density, group, false);
}
private static Material newMaterial(Type type, String baseName, double density) {
return newMaterial(type, baseName, density, null);
}

View File

@ -5,6 +5,8 @@ import info.openrocket.core.startup.Application;
import info.openrocket.core.unit.Unit;
import info.openrocket.core.unit.UnitGroup;
import info.openrocket.core.util.MathUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A class for different material types. Each material has a name and density.
@ -17,8 +19,8 @@ import info.openrocket.core.util.MathUtil;
*/
public abstract class Material implements Comparable<Material> {
private static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(Material.class);
public enum Type {
BULK("Databases.materials.types.Bulk", UnitGroup.UNITS_DENSITY_BULK),
@ -48,6 +50,10 @@ public abstract class Material implements Comparable<Material> {
///// Definitions of different material types /////
public static class Line extends Material {
Line(String name, double density, MaterialGroup group, boolean userDefined) {
super(name, density, group, userDefined);
}
Line(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
@ -59,7 +65,11 @@ public abstract class Material implements Comparable<Material> {
}
public static class Surface extends Material {
Surface(String name, double density, MaterialGroup group, boolean userDefined) {
super(name, density, group, userDefined);
}
Surface(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
@ -76,6 +86,10 @@ public abstract class Material implements Comparable<Material> {
}
public static class Bulk extends Material {
Bulk(String name, double density, MaterialGroup group, boolean userDefined) {
super(name, density, group, userDefined);
}
Bulk(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
@ -88,6 +102,10 @@ public abstract class Material implements Comparable<Material> {
public static class Custom extends Material {
Custom(String name, double density, MaterialGroup group, boolean userDefined) {
super(name, density, group, userDefined);
}
Custom(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
@ -103,20 +121,26 @@ public abstract class Material implements Comparable<Material> {
private final String name;
private final double density;
private final boolean userDefined;
private final MaterialGroup group;
/**
* Constructor for materials.
*
* @param name ignored when defining system materials.
* @param key ignored when defining user materials.
* @param density
* @param density: the density of the material.
* @param group the material group.
* @param userDefined true if this is a user defined material, false if it is a system material.
*/
private Material(String name, double density, boolean userDefined) {
private Material(String name, double density, MaterialGroup group, boolean userDefined) {
this.name = name;
this.userDefined = userDefined;
this.density = density;
this.group = group;
this.userDefined = userDefined;
}
private Material(String name, double density, boolean userDefined) {
this(name, density, null, userDefined);
}
public double getDensity() {
@ -136,6 +160,17 @@ public abstract class Material implements Comparable<Material> {
}
public abstract Type getType();
public MaterialGroup getGroup() {
return group;
}
public int getGroupPriority() {
if (group == null) {
return Integer.MAX_VALUE;
}
return group.getPriority();
}
@Override
public String toString() {
@ -154,7 +189,14 @@ public abstract class Material implements Comparable<Material> {
if (this.getClass() != o.getClass())
return false;
Material m = (Material) o;
return ((m.name.equals(this.name)) && MathUtil.equals(m.density, this.density));
return ((m.name.equals(this.name)) && MathUtil.equals(m.density, this.density)) && groupsEqual(m);
}
private boolean groupsEqual(Material m) {
if (group == null) {
return m.group == null;
}
return group.equals(m.group);
}
@ -187,37 +229,37 @@ public abstract class Material implements Comparable<Material> {
* @param type the material type
* @param name the material name
* @param density the material density
* @param group the material group
* @param userDefined whether the material is user-defined or not
* @return the new material
*/
public static Material newMaterial(Type type, String name, double density, MaterialGroup group, boolean userDefined) {
return switch (type) {
case LINE -> new Line(name, density, group, userDefined);
case SURFACE -> new Surface(name, density, group, userDefined);
case BULK -> new Bulk(name, density, group, userDefined);
case CUSTOM -> new Custom(name, density, group, userDefined);
default -> throw new IllegalArgumentException("Unknown material type: " + type);
};
}
public static Material newMaterial(Type type, String name, double density, boolean userDefined) {
switch (type) {
case LINE:
return new Material.Line(name, density, userDefined);
case SURFACE:
return new Material.Surface(name, density, userDefined);
case BULK:
return new Material.Bulk(name, density, userDefined);
case CUSTOM:
return new Material.Custom(name, density, userDefined);
default:
throw new IllegalArgumentException("Unknown material type: " + type);
}
return newMaterial(type, name, density, null, userDefined);
}
public String toStorableString() {
return getType().name() + "|" + name.replace('|', ' ') + '|' + density;
if (group != null) {
return getType().name() + "|" + name.replace('|', ' ') + '|' + density + '|' + group.getDatabaseString();
} else {
return getType().name() + "|" + name.replace('|', ' ') + '|' + density;
}
}
/**
* Return a material defined by the provided string.
*
* @param str the material storage string, formatted as "{type}|{name}|{density}".
* @param str the material storage string, formatted as "{type}|{name}|{density}|{group}".
* @param userDefined whether the created material is user-defined.
* @return a new <code>Material</code> object.
* @throws IllegalArgumentException if <code>str</code> is invalid or null.
@ -226,13 +268,14 @@ public abstract class Material implements Comparable<Material> {
if (str == null)
throw new IllegalArgumentException("Material string is null");
String[] split = str.split("\\|", 3);
String[] split = str.split("\\|", 4);
if (split.length < 3)
throw new IllegalArgumentException("Illegal material string: " + str);
Type type = null;
Type type;
String name;
double density;
MaterialGroup group = null;
try {
type = Type.valueOf(split[0]);
@ -247,20 +290,21 @@ public abstract class Material implements Comparable<Material> {
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Illegal material string: " + str, e);
}
switch (type) {
case BULK:
return new Material.Bulk(name, density, userDefined);
case SURFACE:
return new Material.Surface(name, density, userDefined);
case LINE:
return new Material.Line(name, density, userDefined);
default:
throw new IllegalArgumentException("Illegal material string: " + str);
if (split.length == 4) {
try {
group = MaterialGroup.loadFromDatabaseString(split[3]);
} catch (IllegalArgumentException e) {
log.debug(e.toString());
}
}
return switch (type) {
case BULK -> new Bulk(name, density, group, userDefined);
case SURFACE -> new Surface(name, density, group, userDefined);
case LINE -> new Line(name, density, group, userDefined);
default -> throw new IllegalArgumentException("Illegal material string: " + str);
};
}
}

View File

@ -0,0 +1,99 @@
package info.openrocket.core.material;
import info.openrocket.core.l10n.Translator;
import info.openrocket.core.startup.Application;
/**
* A class for categorizing materials.
*/
public class MaterialGroup implements Comparable<MaterialGroup> {
private static final Translator trans = Application.getTranslator();
public static final MaterialGroup METALS = new MaterialGroup(trans.get("MaterialGroup.Metals"), "Metals", 0, false);
public static final MaterialGroup WOODS = new MaterialGroup(trans.get("MaterialGroup.Woods"), "Woods", 10, false);
public static final MaterialGroup PLASTICS = new MaterialGroup(trans.get("MaterialGroup.Plastics"), "Plastics", 20, false);
public static final MaterialGroup FABRICS = new MaterialGroup(trans.get("MaterialGroup.Fabrics"), "Fabrics", 30, false);
public static final MaterialGroup PAPER = new MaterialGroup(trans.get("MaterialGroup.PaperProducts"), "PaperProducts", 40, false);
public static final MaterialGroup FOAMS = new MaterialGroup(trans.get("MaterialGroup.Foams"), "Foams", 50, false);
public static final MaterialGroup COMPOSITES = new MaterialGroup(trans.get("MaterialGroup.Composites"), "Composites", 60, false);
public static final MaterialGroup FIBERS = new MaterialGroup(trans.get("MaterialGroup.Fibers"), "Fibres", 70, false);
public static final MaterialGroup THREADS_LINES = new MaterialGroup(trans.get("MaterialGroup.ThreadsLines"), "ThreadsLines", 80, false);
public static final MaterialGroup OTHER = new MaterialGroup(trans.get("MaterialGroup.Other"), "Other", 90, false);
public static final MaterialGroup CUSTOM = new MaterialGroup(trans.get("MaterialGroup.Custom"), "Custom", 1000, true);
public static final MaterialGroup[] ALL_GROUPS = {
METALS,
WOODS,
PLASTICS,
FABRICS,
PAPER,
FOAMS,
COMPOSITES,
FIBERS,
THREADS_LINES,
OTHER,
CUSTOM
};
private final String name;
private final String databaseString;
private final int priority;
private final boolean userDefined;
/**
* Create a new material group.
* @param name the name of the group
* @param dataBaseName the name of the group to be used when saving it in a database
* @param priority the priority of the group (lower number = higher priority)
* @param userDefined whether the group is user-defined
*/
private MaterialGroup(String name, String dataBaseName, int priority, boolean userDefined) {
this.name = name;
this.databaseString = dataBaseName;
this.priority = priority;
this.userDefined = userDefined;
}
public String getName() {
return name;
}
public String getDatabaseString() {
return databaseString;
}
public int getPriority() {
return priority;
}
public boolean isUserDefined() {
return userDefined;
}
public static MaterialGroup loadFromDatabaseString(String name) {
for (MaterialGroup group : ALL_GROUPS) {
if (group.getDatabaseString().equals(name)) {
return group;
}
}
throw new IllegalArgumentException("Unknown material group: " + name);
}
@Override
public String toString() {
return getName();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof MaterialGroup))
return false;
return this.compareTo((MaterialGroup) o) == 0;
}
@Override
public int compareTo(MaterialGroup o) {
return this.priority - o.priority;
}
}

View File

@ -1126,6 +1126,8 @@ MaterialPanel.lbl.ComponentFinish.ttip.longA1 = <html>The component finish affec
MaterialPanel.lbl.ComponentFinish.ttip.longA2 = The value indicated is the average roughness height of the surface.
MaterialPanel.but.SetForAll = Set for all
MaterialPanel.but.SetForAll.ttip = Set this finish for all components of the rocket.
MaterialPanel.but.AddCustomMaterial = Add custom material
MaterialPanel.MaterialComboBox.placeholder = Enter the material name
! PlacementPanel
PlacementPanel.title.Placement = Placement
@ -1807,6 +1809,19 @@ material.tubular_nylon_11_mm_7_16_in = Tubular nylon (11 mm, 7/16 in)
material.tubular_nylon_14_mm_9_16_in = Tubular nylon (14 mm, 9/16 in)
material.tubular_nylon_25_mm_1_in = Tubular nylon (25 mm, 1 in)
!MaterialGroup
MaterialGroup.Metals = Metals
MaterialGroup.Woods = Woods
MaterialGroup.Plastics = Plastics
MaterialGroup.Fabrics = Fabrics
MaterialGroup.PaperProducts = Paper Products
MaterialGroup.Foams = Foams
MaterialGroup.Composites = Composites
MaterialGroup.Fibers = Fibers
MaterialGroup.ThreadsLines = Threads and Lines
MaterialGroup.Other = Other
MaterialGroup.Custom = Custom
! ExternalComponent
ExternalComponent.Rough = Rough
ExternalComponent.Roughunfinished = Rough unfinished

View File

@ -25,10 +25,6 @@ public class MaterialModel extends AbstractListModel<Material> implements
ComboBoxModel<Material>, ComponentChangeListener, DatabaseListener<Material>, Invalidatable {
private static final long serialVersionUID = 4552478532933113655L;
private final ModelInvalidator modelInvalidator;
private final Material custom;
private final Component parentUIComponent;
@ -53,23 +49,22 @@ public class MaterialModel extends AbstractListModel<Material> implements
this.parentUIComponent = parent;
this.rocketComponent = component;
this.type = type;
this.custom = Material.newMaterial( Material.Type.CUSTOM, trans.get ("Material.CUSTOM"), 1.0, true );
switch (type) {
case LINE:
this.database = Databases.LINE_MATERIAL;
break;
case BULK:
this.database = Databases.BULK_MATERIAL;
break;
case SURFACE:
this.database = Databases.SURFACE_MATERIAL;
break;
default:
throw new IllegalArgumentException("Unknown material type:"+type);
case LINE:
this.database = Databases.LINE_MATERIAL;
break;
case BULK:
this.database = Databases.BULK_MATERIAL;
break;
case SURFACE:
this.database = Databases.SURFACE_MATERIAL;
break;
default:
throw new IllegalArgumentException("Unknown material type:"+type);
}
try {
@ -97,55 +92,53 @@ public class MaterialModel extends AbstractListModel<Material> implements
return;
}
if (item == custom) {
// Open custom material dialog in the future, after combo box has closed
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
CustomMaterialDialog dialog = new CustomMaterialDialog(
SwingUtilities.getWindowAncestor(parentUIComponent),
(Material) getSelectedItem(), true,
//// Define custom material
trans.get("MaterialModel.title.Defcustmat"));
dialog.setVisible(true);
if (!dialog.getOkClicked())
return;
Material material = dialog.getMaterial();
setMethod.invoke(rocketComponent, material);
if (dialog.isAddSelected()) {
database.add(material);
}
}
});
} else if (item instanceof Material) {
if (item instanceof Material) {
setMethod.invoke(rocketComponent, item);
} else {
throw new IllegalArgumentException("Illegal item class " + item.getClass() +
" item=" + item);
}
}
public void addCustomMaterial() {
CustomMaterialDialog dialog = new CustomMaterialDialog(
SwingUtilities.getWindowAncestor(parentUIComponent),
(Material) getSelectedItem(), true,
trans.get("MaterialModel.title.Defcustmat"));
dialog.setVisible(true);
if (!dialog.getOkClicked())
return;
Material material = dialog.getMaterial();
setMethod.invoke(rocketComponent, material);
// TODO: add to permanent database if addSelected, add to document database otherwise
if (dialog.isAddSelected()) {
database.add(material);
}
}
@Override
public Material getElementAt(int index) {
if (index == database.size()) {
return custom;
} else if (index >= database.size()+1) {
if (index >= database.size()) {
return null;
}
return database.get(index);
}
public Material[] getAllMaterials() {
Material[] materials = new Material[database.size()];
for (int i = 0; i < database.size(); i++) {
materials[i] = database.get(i);
}
return materials;
}
@Override
public int getSize() {
return database.size() + 1;
return database.size();
}
public Material.Type getType() {
@ -156,7 +149,7 @@ public class MaterialModel extends AbstractListModel<Material> implements
@Override
public void componentChanged(ComponentChangeEvent e) {
if (((ComponentChangeEvent)e).isMassChange()) {
if (e.isMassChange()) {
this.fireContentsChanged(this, 0, 0);
}
}

View File

@ -1,6 +1,8 @@
package info.openrocket.swing.gui.configdialog;
import info.openrocket.core.material.MaterialGroup;
import info.openrocket.core.util.Invalidatable;
import info.openrocket.swing.gui.widgets.SearchableAndCategorizableComboBox;
import net.miginfocom.swing.MigLayout;
import info.openrocket.core.document.OpenRocketDocument;
@ -19,12 +21,17 @@ import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
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.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Panel for configuring a component's material and finish properties.
@ -32,6 +39,7 @@ import java.util.List;
public class MaterialPanel extends JPanel implements Invalidatable, InvalidatingWidget {
private static final Translator trans = Application.getTranslator();
private final List<Invalidatable> invalidatables = new ArrayList<>();
private SearchableAndCategorizableComboBox<MaterialGroup, Material> materialCombo = null;
public MaterialPanel(RocketComponent component, OpenRocketDocument document,
Material.Type type, String materialString, String finishString,
@ -39,24 +47,43 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
super(new MigLayout());
this.setBorder(BorderFactory.createTitledBorder(trans.get("MaterialPanel.title.Material")));
//// Component material
JLabel label = new JLabel(materialString);
//// The component material affects the weight of the component.
label.setToolTipText(trans.get("MaterialPanel.lbl.ttip.ComponentMaterialAffects"));
this.add(label, "spanx 4, wrap rel");
MaterialModel mm = new MaterialModel(this, component, type, partName);
register(mm);
JComboBox<Material> materialCombo = new JComboBox<>(mm);
//// The component material affects the weight of the component.
materialCombo.setToolTipText(trans.get("MaterialPanel.combo.ttip.ComponentMaterialAffects"));
this.add(materialCombo, "spanx 4, growx, wrap paragraph");
order.add(materialCombo);
// Set custom material button
JButton customMaterialButton = new JButton(trans.get("MaterialPanel.but.AddCustomMaterial"));
customMaterialButton.addActionListener(e -> {
SwingUtilities.invokeLater(new Runnable() {
@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());
}
}
});
});
// Material selection combo box
this.materialCombo = MaterialComboBox.createComboBox(MaterialGroup.ALL_GROUPS, mm.getAllMaterials(), customMaterialButton);
this.materialCombo.setSelectedItem(mm.getSelectedItem());
this.materialCombo.setToolTipText(trans.get("MaterialPanel.combo.ttip.ComponentMaterialAffects"));
this.add(this.materialCombo, "spanx 4, growx, wrap paragraph");
order.add(this.materialCombo);
// No surface finish for internal components
if (!(component instanceof ExternalComponent)) {
return;
}
//// Surface finish
label = new JLabel(finishString);
////<html>The component finish affects the aerodynamic drag of the component.<br>
String tip = trans.get("MaterialPanel.lbl.ComponentFinish.ttip.longA1")
//// The value indicated is the average roughness height of the surface.
+ trans.get("MaterialPanel.lbl.ComponentFinish.ttip.longA2");
@ -122,4 +149,63 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
i.invalidateMe();
}
}
public static class MaterialComboBox extends JComboBox<Material> {
private static final Translator trans = Application.getTranslator();
public static SearchableAndCategorizableComboBox<MaterialGroup, Material> createComboBox(
MaterialGroup[] allGroups, Material[] materials, Component... extraCategoryWidgets) {
final Map<MaterialGroup, Material[]> materialGroupMap = createMaterialGroupMap(allGroups, materials);
return new SearchableAndCategorizableComboBox<>(materialGroupMap, trans.get("MaterialPanel.MaterialComboBox.placeholder"), extraCategoryWidgets);
}
public static void updateComboBoxItems(SearchableAndCategorizableComboBox<MaterialGroup, Material> comboBox,
MaterialGroup[] allGroups, Material[] materials) {
final Map<MaterialGroup, Material[]> 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<MaterialGroup, Material[]> 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<MaterialGroup, Material[]> map = new LinkedHashMap<>();
MaterialGroup materialGroup;
for (MaterialGroup group : sortedGroups) {
List<Material> itemsForGroup = new ArrayList<>();
for (Material material : materials) {
materialGroup = material.getGroup();
if (materialGroup == null) {
if (material.isUserDefined()) {
materialGroup = MaterialGroup.CUSTOM;
} else {
materialGroup = MaterialGroup.OTHER;
}
}
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.toArray(new Material[0]));
}
// Remove empty groups
map.entrySet().removeIf(entry -> entry.getValue().length == 0);
return map;
}
}
}

View File

@ -22,6 +22,8 @@ import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
@ -43,17 +45,21 @@ import java.util.TreeSet;
* If no text is entered, the combobox items are displayed in a categorized popup menu, grouped according to their groups.
* @param <E> The type of the group
* @param <T> The type of the items
*
* @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/
public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
private final JPopupMenu categoryPopup;
private final JPopupMenu searchPopup;
private final PlaceholderTextField searchFieldCategory;
private final PlaceholderTextField searchFieldSearch;
private final JList<T> filteredList;
private final String placeHolderText;
private JPopupMenu categoryPopup;
private JPopupMenu searchPopup;
private PlaceholderTextField searchFieldCategory;
private PlaceholderTextField searchFieldSearch;
private final Component[] extraCategoryWidgets;
private JList<T> filteredList;
private final T[] allItems;
private final Map<E, T[]> itemGroupMap;
private T[] allItems;
private Map<E, T[]> itemGroupMap;
private int highlightedListIdx = -1;
@ -67,29 +73,17 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
* Create a searchable and categorizable combo box.
* @param itemGroupMap the map of items and their corresponding groups
* @param placeHolderText the placeholder text for the search field (when no text is entered)
* @param extraCategoryWidgets extra widgets to add to the category popup. Each widget will be added as a separate menu item.
*/
public SearchableAndCategorizableComboBox(Map<E, T[]> itemGroupMap, String placeHolderText) {
public SearchableAndCategorizableComboBox(Map<E, T[]> itemGroupMap, String placeHolderText, Component... extraCategoryWidgets) {
super();
setEditable(false);
this.itemGroupMap = itemGroupMap;
this.allItems = extractItemsFromMap(itemGroupMap);
setModel(new DefaultComboBoxModel<>(allItems));
initColors();
// Create the search field widget
searchFieldCategory = new PlaceholderTextField();
searchFieldCategory.setPlaceholder(placeHolderText);
searchFieldSearch = new PlaceholderTextField();
// Create the filtered list
filteredList = createFilteredList();
// Create the different popups
categoryPopup = createCategoryPopup();
searchPopup = createSearchPopup();
searchPopup.setPreferredSize(categoryPopup.getPreferredSize());
this.extraCategoryWidgets = extraCategoryWidgets;
this.placeHolderText = placeHolderText;
updateItems(itemGroupMap);
// Add key listener for the search fields
searchFieldCategory.addKeyListener(new KeyAdapter() {
@ -98,6 +92,7 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
overrideActionKeys(e);
}
@Override
public void keyTyped(KeyEvent e) {
EventQueue.invokeLater(() -> {
String text = searchFieldCategory.getText();
@ -131,6 +126,16 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
});
}
});
// Fix a bug where the first character would get selected when the search field gets focus (thus deleting it on
// the next key press)
searchFieldSearch.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
SwingUtilities.invokeLater(() -> {
searchFieldSearch.setCaretPosition(searchFieldSearch.getText().length());
});
}
});
// Override the mouse listeners to use our custom popup
for (MouseListener mouseListener : getMouseListeners()) {
@ -149,6 +154,25 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
textSelectionBackground = GUIUtil.getUITheme().getTextSelectionBackgroundColor();
}
public void updateItems(Map<E, T[]> itemGroupMap) {
this.itemGroupMap = itemGroupMap;
this.allItems = extractItemsFromMap(itemGroupMap);
setModel(new DefaultComboBoxModel<>(this.allItems));
// Create the search field widget
this.searchFieldCategory = new PlaceholderTextField();
this.searchFieldCategory.setPlaceholder(this.placeHolderText);
this.searchFieldSearch = new PlaceholderTextField();
// Create the filtered list
this.filteredList = createFilteredList();
// Create the different popups
this.categoryPopup = createCategoryPopup();
this.searchPopup = createSearchPopup();
this.searchPopup.setPreferredSize(this.categoryPopup.getPreferredSize());
}
private T[] extractItemsFromMap(Map<E, T[]> itemGroupMap) {
Set<T> uniqueItems = new HashSet<>(); // Use a Set to ensure uniqueness
for (E group : itemGroupMap.keySet()) {
@ -183,6 +207,13 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
menu.add(groupList);
}
// Extra widgets
if (extraCategoryWidgets != null) {
for (Component widget : extraCategoryWidgets) {
menu.add(widget);
}
}
return menu;
}