package org.openslx.dozmod.gui.control; import java.awt.Component; import java.util.Comparator; import javax.swing.ComboBoxModel; import javax.swing.DefaultListCellRenderer; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; @SuppressWarnings("serial") public class ComboBox extends JComboBox { public static abstract class ComboBoxRenderer { public abstract String renderItem(T item); public String getEmptyText() { return null; } } private final Comparator equalityComparator; private final ComboBoxRenderer itemRenderer; private final ComboBox me = this; private boolean replacedRenderer = false; public ComboBox(ComboBoxRenderer renderer) { this(null, renderer); } public ComboBox(Comparator equalityComparator, ComboBoxRenderer renderer) { super(); this.itemRenderer = renderer; this.equalityComparator = equalityComparator; } /** * This version of {@link JComboBox#setSelectedItem(Object)} will use the * comparator given when constructing the ComboBox to determine if an entry * should be selected. */ @SuppressWarnings("unchecked") @Override public void setSelectedItem(Object anObject) { if (anObject != null && equalityComparator != null) { ComboBoxModel model = getModel(); Object localObject = null; try { for (int i = 0; i < model.getSize(); ++i) { T element = model.getElementAt(i); if (equalityComparator.compare((T) anObject, element) == 0) { localObject = element; break; } } super.setSelectedItem(localObject); return; } catch (ClassCastException e) { // Bummer, fall through } } super.setSelectedItem(anObject); } @Override public void updateUI() { super.updateUI(); if (!replacedRenderer) { replacedRenderer = true; final ListCellRenderer oldRenderer = super.getRenderer(); if (oldRenderer instanceof JLabel) { // The default JComboBox renderer always seems to be a subclass of JLabel, which is nice ((JLabel) oldRenderer).putClientProperty("html.disable", Boolean.TRUE); ((JLabel) oldRenderer).putClientProperty("html", null); super.setRenderer(new ListCellRenderer() { @Override public Component getListCellRendererComponent(JList list, T value, int index, boolean isSelected, boolean cellHasFocus) { String text; if (me.getModel().getSize() == 0) { text = itemRenderer.getEmptyText(); } else { text = itemRenderer.renderItem(value); } Component comp = oldRenderer.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus); comp.setEnabled(me.isEnabled()); ((JLabel) comp).setText(text); return comp; } }); } else { // Fallback, in case there's any platform, L&F, runtime environment or whatnot where it's not a JLabel super.setRenderer(new FallbackCellRenderer()); } } } private class FallbackCellRenderer extends DefaultListCellRenderer { public FallbackCellRenderer() { putClientProperty("html.disable", Boolean.TRUE); putClientProperty("html", null); } @SuppressWarnings("unchecked") @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (me.getModel().getSize() == 0) { value = itemRenderer.getEmptyText(); } else { try { value = itemRenderer.renderItem((T) value); } catch (ClassCastException e) { // Should never happen; do nothing, retain original value } } return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); } } }