package com.onaro.util.jfc; import java.awt.Dimension; import javax.swing.ComboBoxModel; import javax.swing.JList; import javax.swing.event.ListDataEvent; import com.onaro.commons.swing.OnaroSwingUtilities; public class OnaroDynamicComboBox extends OnaroComboBox { private static final long serialVersionUID = 1L; /* * Extra padding necessary to account for drop-down list box decoration * that increases its width beyond that of the text it contains. * Unfortunately, its hard to determine a platform-independent value. * But it's OK to err on the high side. */ private static int PADDING = 6; /* * List used only to determine width of items in the drop-down list box. * Would like to use JComboBox.popupList, but unfortunately it's * private and doesn't have an accessor. */ private JList dropDownList; /** * Create a combo box containing the given items. The box will be * as wide as the widest given item string. Its size will not vary. *

* The drop-down list will initially be the same width as the box. * It will be made wider if wider items are added. It will not narrow. * * @param items Objects selected in drop-down list */ @SafeVarargs public OnaroDynamicComboBox (T... items) { super (items); dropDownList = new JList (items); } /** * Create a combo box containing the given items. The box will be as * wide as the widest given item string up to the specified maximum width. * Its size will not vary. The drop-down list will initially be as wide as * necessary to show all the given item strings. *

* The drop-down list will initially be the same width as the box. * It will be made wider if wider items are added. It will not narrow. *

* If {@link #setPreferredSize} or {@link #setPreferredSize} is invoked * before the box is rendered, then the arguments passed to those methods * will determine the box and initial list size. * * @param maxBoxWidth Maximum allowed width of the box * @param items Objects selected in drop-down list */ @SafeVarargs public OnaroDynamicComboBox (int maxBoxWidth, T... items) { super (maxBoxWidth, items); dropDownList = new JList (items); } @Override public void setModel (ComboBoxModel model) { super.setModel (model); dropDownList = new JList (model); } @Override public void intervalAdded (ListDataEvent event) { ComboBoxModel model = getModel(); if (model != null) { adjustWidth (event, model); } super.intervalAdded (event); } private void adjustWidth (final ListDataEvent event, final ComboBoxModel model) { // Get bounds of interval. Note bounds are inclusive. int first = event.getIndex0(); if (first < 0) { first = 0; } int last = event.getIndex1(); if (last < 0 || last >= model.getSize()) { last = model.getSize() - 1; } // Get current metrics. Dimension size = getSize(); int listWidth = size.width; // Determine new size. for (int i = first; i <= last; i++) { T item = model.getElementAt (i); // Allow room to display item with selection and focus. int itemWidth = getRenderer() .getListCellRendererComponent (dropDownList, item, i, false, false) .getPreferredSize().width + PADDING; if (i >= getMaximumRowCount()) { if (i == getMaximumRowCount()) { // Increase list width to allow for the scroll bar that will be added. listWidth += OnaroSwingUtilities.getDefaultScrollBarWidth(); } // Increase item width to allow for the scroll bar. itemWidth += OnaroSwingUtilities.getDefaultScrollBarWidth(); } listWidth = Math.max (listWidth, itemWidth); } // Adjust size. if (listWidth != size.width) { size.width = listWidth; setSize (size); } } }