Refactor SearchableAndCategorizableComboBox to use Group and Groupable interface

This commit is contained in:
SiboVG 2024-08-07 14:19:46 +02:00
parent 691f79fe3c
commit e3ce3ac7dd
9 changed files with 142 additions and 60 deletions

View File

@ -4,6 +4,7 @@ import info.openrocket.core.l10n.Translator;
import info.openrocket.core.startup.Application; import info.openrocket.core.startup.Application;
import info.openrocket.core.unit.Unit; import info.openrocket.core.unit.Unit;
import info.openrocket.core.unit.UnitGroup; import info.openrocket.core.unit.UnitGroup;
import info.openrocket.core.util.Groupable;
import info.openrocket.core.util.MathUtil; import info.openrocket.core.util.MathUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -18,7 +19,7 @@ import org.slf4j.LoggerFactory;
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public abstract class Material implements Comparable<Material> { public abstract class Material implements Comparable<Material>, Groupable<MaterialGroup> {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(Material.class); private static final Logger log = LoggerFactory.getLogger(Material.class);

View File

@ -2,11 +2,12 @@ package info.openrocket.core.material;
import info.openrocket.core.l10n.Translator; import info.openrocket.core.l10n.Translator;
import info.openrocket.core.startup.Application; import info.openrocket.core.startup.Application;
import info.openrocket.core.util.Group;
/** /**
* A class for categorizing materials. * A class for categorizing materials.
*/ */
public class MaterialGroup implements Comparable<MaterialGroup> { public class MaterialGroup implements Comparable<MaterialGroup>, Group {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
// When modifying this list, also update the MaterialGroupDTO class in the preset.xml package! (and the ALL_GROUPS array) // When modifying this list, also update the MaterialGroupDTO class in the preset.xml package! (and the ALL_GROUPS array)

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import info.openrocket.core.util.Groupable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -32,7 +33,7 @@ import info.openrocket.core.util.StringUtils;
* *
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public class FlightDataType implements Comparable<FlightDataType> { public class FlightDataType implements Comparable<FlightDataType>, Groupable<FlightDataTypeGroup> {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
private static final Logger log = LoggerFactory.getLogger(FlightDataType.class); private static final Logger log = LoggerFactory.getLogger(FlightDataType.class);

View File

@ -2,8 +2,9 @@ package info.openrocket.core.simulation;
import info.openrocket.core.l10n.Translator; import info.openrocket.core.l10n.Translator;
import info.openrocket.core.startup.Application; import info.openrocket.core.startup.Application;
import info.openrocket.core.util.Group;
public class FlightDataTypeGroup implements Comparable<FlightDataTypeGroup> { public class FlightDataTypeGroup implements Comparable<FlightDataTypeGroup>, Group {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
public static final FlightDataTypeGroup TIME = new FlightDataTypeGroup(trans.get("FlightDataTypeGroup.GROUP_TIME"), 0); public static final FlightDataTypeGroup TIME = new FlightDataTypeGroup(trans.get("FlightDataTypeGroup.GROUP_TIME"), 0);

View File

@ -0,0 +1,9 @@
package info.openrocket.core.util;
/**
* Interface for objects that a <Groupable> object can be grouped into.
*/
public interface Group {
String getName();
int getPriority(); // Lower number = higher priority (can be used for sorting)
}

View File

@ -0,0 +1,9 @@
package info.openrocket.core.util;
/**
* Interface for objects that can be grouped into a <Group> object.
* @param <G> the group type
*/
public interface Groupable<G extends Group> {
G getGroup();
}

View File

@ -89,13 +89,9 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
}); });
// Material selection combo box // Material selection combo box
this.materialCombo = MaterialComboBox.createComboBox(MaterialGroup.ALL_GROUPS, mm.getAllMaterials(), this.materialCombo = MaterialComboBox.createComboBox(mm, MaterialGroup.ALL_GROUPS, mm.getAllMaterials(),
customMaterialButton, editMaterialsButton); customMaterialButton, editMaterialsButton);
this.materialCombo.setSelectedItem(mm.getSelectedItem()); this.materialCombo.setSelectedItem(mm.getSelectedItem());
this.materialCombo.addActionListener(e -> {
Material selectedMaterial = (Material) materialCombo.getSelectedItem();
mm.setSelectedItem(selectedMaterial);
});
this.materialCombo.setToolTipText(trans.get("MaterialPanel.combo.ttip.ComponentMaterialAffects")); this.materialCombo.setToolTipText(trans.get("MaterialPanel.combo.ttip.ComponentMaterialAffects"));
this.add(this.materialCombo, "spanx 4, growx, wrap paragraph"); this.add(this.materialCombo, "spanx 4, growx, wrap paragraph");
order.add(this.materialCombo); order.add(this.materialCombo);
@ -175,9 +171,10 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
public static SearchableAndCategorizableComboBox<MaterialGroup, Material> createComboBox( public static SearchableAndCategorizableComboBox<MaterialGroup, Material> createComboBox(
MaterialGroup[] allGroups, Material[] materials, Component... extraCategoryWidgets) { MaterialModel mm, MaterialGroup[] allGroups, Material[] materials, Component... extraCategoryWidgets) {
final Map<MaterialGroup, Material[]> materialGroupMap = createMaterialGroupMap(allGroups, materials); final Map<MaterialGroup, List<Material>> materialGroupMap =
return new SearchableAndCategorizableComboBox<>(materialGroupMap, createMaterialGroupMap(allGroups, materials);
return new SearchableAndCategorizableComboBox<>(mm, materialGroupMap,
trans.get("MaterialPanel.MaterialComboBox.placeholder"), extraCategoryWidgets) { trans.get("MaterialPanel.MaterialComboBox.placeholder"), extraCategoryWidgets) {
@Override @Override
public String getDisplayString(Material item) { public String getDisplayString(Material item) {
@ -192,7 +189,7 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
public static void updateComboBoxItems(SearchableAndCategorizableComboBox<MaterialGroup, Material> comboBox, public static void updateComboBoxItems(SearchableAndCategorizableComboBox<MaterialGroup, Material> comboBox,
MaterialGroup[] allGroups, Material[] materials) { MaterialGroup[] allGroups, Material[] materials) {
final Map<MaterialGroup, Material[]> materialGroupMap = createMaterialGroupMap(allGroups, materials); final Map<MaterialGroup, List<Material>> materialGroupMap = createMaterialGroupMap(allGroups, materials);
comboBox.updateItems(materialGroupMap); comboBox.updateItems(materialGroupMap);
comboBox.invalidate(); comboBox.invalidate();
comboBox.repaint(); comboBox.repaint();
@ -204,13 +201,13 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
* @param materials the materials * @param materials the materials
* @return the map linking the materials to their groups * @return the map linking the materials to their groups
*/ */
private static Map<MaterialGroup, Material[]> createMaterialGroupMap( private static Map<MaterialGroup, List<Material>> createMaterialGroupMap(
MaterialGroup[] groups, Material[] materials) { MaterialGroup[] groups, Material[] materials) {
// Sort the groups based on priority (lower number = higher priority) // Sort the groups based on priority (lower number = higher priority)
MaterialGroup[] sortedGroups = groups.clone(); MaterialGroup[] sortedGroups = groups.clone();
Arrays.sort(sortedGroups, Comparator.comparingInt(MaterialGroup::getPriority)); Arrays.sort(sortedGroups, Comparator.comparingInt(MaterialGroup::getPriority));
Map<MaterialGroup, Material[]> map = new LinkedHashMap<>(); Map<MaterialGroup, List<Material>> map = new LinkedHashMap<>();
MaterialGroup materialGroup; MaterialGroup materialGroup;
for (MaterialGroup group : sortedGroups) { for (MaterialGroup group : sortedGroups) {
List<Material> itemsForGroup = new ArrayList<>(); List<Material> itemsForGroup = new ArrayList<>();
@ -223,11 +220,11 @@ public class MaterialPanel extends JPanel implements Invalidatable, Invalidating
// Sort the types within each group based on priority // Sort the types within each group based on priority
itemsForGroup.sort(Comparator.comparingInt(Material::getGroupPriority)); itemsForGroup.sort(Comparator.comparingInt(Material::getGroupPriority));
map.put(group, itemsForGroup.toArray(new Material[0])); map.put(group, itemsForGroup);
} }
// Remove empty groups // Remove empty groups
map.entrySet().removeIf(entry -> entry.getValue().length == 0); map.entrySet().removeIf(entry -> entry.getValue().isEmpty());
return map; return map;
} }

View File

@ -18,7 +18,7 @@ public class FlightDataComboBox extends JComboBox<FlightDataType> {
private static final Translator trans = Application.getTranslator(); private static final Translator trans = Application.getTranslator();
public static SearchableAndCategorizableComboBox<FlightDataTypeGroup, FlightDataType> createComboBox(FlightDataTypeGroup[] allGroups, FlightDataType[] types) { public static SearchableAndCategorizableComboBox<FlightDataTypeGroup, FlightDataType> createComboBox(FlightDataTypeGroup[] allGroups, FlightDataType[] types) {
final Map<FlightDataTypeGroup, FlightDataType[]> typeGroupMap = createFlightDataGroupMap(allGroups, types); final Map<FlightDataTypeGroup, List<FlightDataType>> typeGroupMap = createFlightDataGroupMap(allGroups, types);
return new SearchableAndCategorizableComboBox<>(typeGroupMap, trans.get("FlightDataComboBox.placeholder")); return new SearchableAndCategorizableComboBox<>(typeGroupMap, trans.get("FlightDataComboBox.placeholder"));
} }
@ -28,13 +28,13 @@ public class FlightDataComboBox extends JComboBox<FlightDataType> {
* @param types the types * @param types the types
* @return the map linking the types to their groups * @return the map linking the types to their groups
*/ */
private static Map<FlightDataTypeGroup, FlightDataType[]> createFlightDataGroupMap( private static Map<FlightDataTypeGroup, List<FlightDataType>> createFlightDataGroupMap(
FlightDataTypeGroup[] groups, FlightDataType[] types) { FlightDataTypeGroup[] groups, FlightDataType[] types) {
// Sort the groups based on priority (lower number = higher priority) // Sort the groups based on priority (lower number = higher priority)
FlightDataTypeGroup[] sortedGroups = groups.clone(); FlightDataTypeGroup[] sortedGroups = groups.clone();
Arrays.sort(sortedGroups, Comparator.comparingInt(FlightDataTypeGroup::getPriority)); Arrays.sort(sortedGroups, Comparator.comparingInt(FlightDataTypeGroup::getPriority));
Map<FlightDataTypeGroup, FlightDataType[]> map = new LinkedHashMap<>(); Map<FlightDataTypeGroup, List<FlightDataType>> map = new LinkedHashMap<>();
for (FlightDataTypeGroup group : sortedGroups) { for (FlightDataTypeGroup group : sortedGroups) {
List<FlightDataType> itemsForGroup = new ArrayList<>(); List<FlightDataType> itemsForGroup = new ArrayList<>();
for (FlightDataType type : types) { for (FlightDataType type : types) {
@ -45,7 +45,7 @@ public class FlightDataComboBox extends JComboBox<FlightDataType> {
// Sort the types within each group based on priority // Sort the types within each group based on priority
itemsForGroup.sort(Comparator.comparingInt(FlightDataType::getGroupPriority)); itemsForGroup.sort(Comparator.comparingInt(FlightDataType::getGroupPriority));
map.put(group, itemsForGroup.toArray(new FlightDataType[0])); map.put(group, itemsForGroup);
} }
return map; return map;

View File

@ -1,9 +1,12 @@
package info.openrocket.swing.gui.widgets; package info.openrocket.swing.gui.widgets;
import info.openrocket.core.util.Group;
import info.openrocket.core.util.Groupable;
import info.openrocket.swing.gui.util.GUIUtil; import info.openrocket.swing.gui.util.GUIUtil;
import info.openrocket.swing.gui.theme.UITheme; import info.openrocket.swing.gui.theme.UITheme;
import javax.swing.AbstractListModel; import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer; import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox; import javax.swing.JComboBox;
@ -13,7 +16,10 @@ import javax.swing.JMenu;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.MutableComboBoxModel;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.basic.BasicArrowButton; import javax.swing.plaf.basic.BasicArrowButton;
@ -34,23 +40,26 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.Vector;
/** /**
* A combo box that has a search box for searching the items in the combobox. * A combo box that has a search box for searching the items in the combobox.
* If no text is entered, the combobox items are displayed in a categorized popup menu, grouped according to their groups. * 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 <G> The type of the group
* @param <T> The type of the items * @param <T> The type of the groupable items
* *
* @author Sibo Van Gool <sibo.vangool@hotmail.com> * @author Sibo Van Gool <sibo.vangool@hotmail.com>
*/ */
public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> { public class SearchableAndCategorizableComboBox<G extends Group, T extends Groupable<G>> extends JComboBox<T> {
private final String placeHolderText; private final String placeHolderText;
private JPopupMenu categoryPopup; private JPopupMenu categoryPopup;
private JPopupMenu searchPopup; private JPopupMenu searchPopup;
@ -59,13 +68,15 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
private final Component[] extraCategoryWidgets; private final Component[] extraCategoryWidgets;
private JList<T> filteredList; private JList<T> filteredList;
private T[] allItems; private Map<G, List<T>> itemGroupMap;
private Map<E, T[]> itemGroupMap; private List<T> allItems;
private int highlightedListIdx = -1; private int highlightedListIdx = -1;
private static Color textSelectionBackground; private static Color textSelectionBackground;
private static final String CHECKMARK = "\u2713";
static { static {
initColors(); initColors();
} }
@ -76,8 +87,9 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
* @param placeHolderText the placeholder text for the search field (when no text is entered) * @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. * @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, Component... extraCategoryWidgets) { public SearchableAndCategorizableComboBox(ComboBoxModel<T> model, Map<G, List<T>> itemGroupMap, String placeHolderText,
super(); Component... extraCategoryWidgets) {
super(model != null ? model : new DefaultComboBoxModel<>());
setEditable(false); setEditable(false);
initColors(); initColors();
@ -87,6 +99,25 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
updateItems(itemGroupMap); updateItems(itemGroupMap);
setupMainRenderer(); setupMainRenderer();
if (model != null) {
model.addListDataListener(new ListDataListener() {
@Override
public void intervalAdded(ListDataEvent e) {
updateItemsFromModel();
}
@Override
public void intervalRemoved(ListDataEvent e) {
updateItemsFromModel();
}
@Override
public void contentsChanged(ListDataEvent e) {
updateItemsFromModel();
}
});
}
// Add key listener for the search fields // Add key listener for the search fields
searchFieldCategory.addKeyListener(new KeyAdapter() { searchFieldCategory.addKeyListener(new KeyAdapter() {
@Override @Override
@ -147,6 +178,10 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
addMouseListeners(); addMouseListeners();
} }
public SearchableAndCategorizableComboBox(Map<G, List<T>> itemGroupMap, String placeHolderText, Component... extraCategoryWidgets) {
this(null, itemGroupMap, placeHolderText, extraCategoryWidgets);
}
private static void initColors() { private static void initColors() {
updateColors(); updateColors();
UITheme.Theme.addUIThemeChangeListener(SearchableAndCategorizableComboBox::updateColors); UITheme.Theme.addUIThemeChangeListener(SearchableAndCategorizableComboBox::updateColors);
@ -169,32 +204,68 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
}); });
} }
public void updateItems(Map<E, T[]> itemGroupMap) { public void updateItems(Map<G, List<T>> itemGroupMap) {
this.itemGroupMap = itemGroupMap; this.itemGroupMap = new LinkedHashMap<>(itemGroupMap); // Create a copy to avoid external modifications
this.allItems = extractItemsFromMap(itemGroupMap); this.allItems = extractItemsFromMap(itemGroupMap);
setModel(new DefaultComboBoxModel<>(this.allItems));
// Create the search field widget // Update the existing model instead of creating a new one
this.searchFieldCategory = new PlaceholderTextField(); ComboBoxModel<T> model = getModel();
this.searchFieldCategory.setPlaceholder(this.placeHolderText); if (model instanceof MutableComboBoxModel<T> mutableModel) {
this.searchFieldSearch = new PlaceholderTextField();
// Create the filtered list // Remove all existing elements
while (mutableModel.getSize() > 0) {
mutableModel.removeElementAt(0);
}
// Add new elements
for (T item : allItems) {
mutableModel.addElement(item);
}
} else {
// If the model is not mutable, we need to set a new model
// This should be a rare case, as DefaultComboBoxModel is mutable
setModel(new DefaultComboBoxModel<>(new Vector<>(allItems)));
}
// Recreate the search fields only if they don't exist
if (this.searchFieldCategory == null) {
this.searchFieldCategory = new PlaceholderTextField();
this.searchFieldCategory.setPlaceholder(this.placeHolderText);
}
if (this.searchFieldSearch == null) {
this.searchFieldSearch = new PlaceholderTextField();
}
// Recreate the filtered list and popups
this.filteredList = createFilteredList(); this.filteredList = createFilteredList();
// Create the different popups
this.categoryPopup = createCategoryPopup(); this.categoryPopup = createCategoryPopup();
this.searchPopup = createSearchPopup(); this.searchPopup = createSearchPopup();
this.searchPopup.setPreferredSize(this.categoryPopup.getPreferredSize()); this.searchPopup.setPreferredSize(this.categoryPopup.getPreferredSize());
revalidate();
repaint();
} }
private T[] extractItemsFromMap(Map<E, T[]> itemGroupMap) { private void updateItemsFromModel() {
Set<T> uniqueItems = new HashSet<>(); // Use a Set to ensure uniqueness ComboBoxModel<T> model = getModel();
for (E group : itemGroupMap.keySet()) { Map<G, List<T>> newGroupMap = new HashMap<>();
uniqueItems.addAll(Arrays.asList(itemGroupMap.get(group)));
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);
} }
ArrayList<T> items = new ArrayList<>(uniqueItems);
return items.toArray((T[]) new Object[0]); Map<G, List<T>> newItemGroupMap = new HashMap<>(newGroupMap);
updateItems(newItemGroupMap);
}
private List<T> extractItemsFromMap(Map<G, List<T>> itemGroupMap) {
Set<T> uniqueItems = new HashSet<>(); // Use a Set to ensure uniqueness
for (G group : itemGroupMap.keySet()) {
uniqueItems.addAll(itemGroupMap.get(group));
}
return new ArrayList<>(uniqueItems);
} }
private JPopupMenu createCategoryPopup() { private JPopupMenu createCategoryPopup() {
@ -205,18 +276,18 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
menu.addSeparator(); // Separator between search field and menu items menu.addSeparator(); // Separator between search field and menu items
// Fill the menu with the groups // Fill the menu with the groups
for (E group : itemGroupMap.keySet()) { for (G group : itemGroupMap.keySet()) {
JMenu groupMenu = new JMenu(group.toString()) { JMenu groupMenu = new JMenu(group.toString()) {
@Override @Override
public void paintComponent(Graphics g) { public void paintComponent(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
// If the group contains the selected item, draw a checkbox // If the group contains the selected item, draw a checkbox
if (containsSelectedItem(group, (T) SearchableAndCategorizableComboBox.this.getSelectedItem())) { if (containsSelectedItem(group, (T) SearchableAndCategorizableComboBox.this.getSelectedItem())) {
g.drawString("\u2713", 5, getHeight() - 5); // Unicode for checked checkbox g.drawString(CHECKMARK, 5, getHeight() - 5); // Unicode for checked checkbox
} }
} }
}; };
T[] itemsForGroup = itemGroupMap.get(group); List<T> itemsForGroup = itemGroupMap.get(group);
if (itemsForGroup != null) { if (itemsForGroup != null) {
for (T item : itemsForGroup) { for (T item : itemsForGroup) {
@ -226,7 +297,7 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
super.paintComponent(g); super.paintComponent(g);
// If the item is currently selected, draw a checkmark before it // If the item is currently selected, draw a checkmark before it
if (item == SearchableAndCategorizableComboBox.this.getSelectedItem()) { if (item == SearchableAndCategorizableComboBox.this.getSelectedItem()) {
g.drawString("\u2713 ", 5, getHeight() - 5); g.drawString(CHECKMARK + " ", 5, getHeight() - 5);
} }
} }
}; };
@ -279,7 +350,7 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
// If the item is currently selected, draw a checkmark before it // If the item is currently selected, draw a checkmark before it
if (item == getSelectedItem()) { if (item == getSelectedItem()) {
itemName = "\u2713 " + itemName; itemName = CHECKMARK + " " + itemName;
} }
if (itemName.toLowerCase().contains(searchFieldSearch.getText().toLowerCase())) { if (itemName.toLowerCase().contains(searchFieldSearch.getText().toLowerCase())) {
@ -358,16 +429,8 @@ public class SearchableAndCategorizableComboBox<E, T> extends JComboBox<T> {
searchPopup.setVisible(false); searchPopup.setVisible(false);
} }
private boolean containsSelectedItem(E group, T targetItem) { private boolean containsSelectedItem(G group, T targetItem) {
T[] itemsInGroup = itemGroupMap.get(group); return targetItem != null && targetItem.getGroup().equals(group);
if (itemsInGroup != null) {
for (T item : itemsInGroup) {
if (item == targetItem) {
return true;
}
}
}
return false;
} }
private void filter(String text) { private void filter(String text) {